maildir-storage.c revision 37847ec8eaec9ad55c9df10ae109efe7b37ac573
e364bf323ef28133cdf28e6b31bad47999cdbe49Timo Sirainen/* Copyright (c) 2002-2009 Dovecot authors, see the included COPYING file */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include "lib.h"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include "ioloop.h"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include "array.h"
d39a04db2f4d0599cb9b5f03a9aa10a3c234453cTimo Sirainen#include "hostpid.h"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include "str.h"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include "mkdir-parents.h"
a3fe8c0c54d87822f4b4f8f0d10caac611861b2bTimo Sirainen#include "eacces-error.h"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include "unlink-directory.h"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include "unlink-old-files.h"
c99fe55d4535d839a6ad0735c4719e076a1adb2cTimo Sirainen#include "mailbox-log.h"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include "mailbox-uidvalidity.h"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include "maildir-storage.h"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include "maildir-uidlist.h"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include "maildir-keywords.h"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include "maildir-sync.h"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include "index-mail.h"
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include <stdio.h>
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include <stdlib.h>
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include <dirent.h>
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include <unistd.h>
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include <sys/stat.h>
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#define MAILDIR_SUBFOLDER_FILENAME "maildirfolder"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#define MAILDIR_LIST_CONTEXT(obj) \
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen MODULE_CONTEXT(obj, maildir_mailbox_list_module)
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainenstruct maildir_mailbox_list {
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen union mailbox_list_module_context module_ctx;
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen const struct maildir_settings *set;
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen};
86791365b10f45982c88e70f2eb94fd6c3fea151Timo Sirainen
86791365b10f45982c88e70f2eb94fd6c3fea151Timo Sirainenstruct rename_context {
86791365b10f45982c88e70f2eb94fd6c3fea151Timo Sirainen bool found;
86791365b10f45982c88e70f2eb94fd6c3fea151Timo Sirainen size_t oldnamelen;
4d4d6d4745682790c20d759ba93dbea46b812c5dTimo Sirainen const char *newname;
4d4d6d4745682790c20d759ba93dbea46b812c5dTimo Sirainen};
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenextern struct mail_storage maildir_storage;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenextern struct mailbox maildir_mailbox;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenstatic MODULE_CONTEXT_DEFINE_INIT(maildir_mailbox_list_module,
17fe695b985e9d6e9dc39c05b24e6b3c3b7e1ba1Timo Sirainen &mailbox_list_module_register);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenstatic const char *maildir_subdirs[] = { "cur", "new", "tmp" };
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenstatic bool maildir_is_internal_name(const char *name)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen{
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return strcmp(name, "cur") == 0 ||
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen strcmp(name, "new") == 0 ||
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen strcmp(name, "tmp") == 0;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen}
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenstatic bool maildir_storage_is_valid_existing_name(struct mailbox_list *list,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen const char *name)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen{
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen struct maildir_mailbox_list *mlist = MAILDIR_LIST_CONTEXT(list);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen const char *p;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (!mlist->module_ctx.super.is_valid_existing_name(list, name))
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return FALSE;
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen /* Don't allow the mailbox name to end in cur/new/tmp */
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen p = strrchr(name, '/');
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen if (p != NULL)
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen name = p + 1;
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen return !maildir_is_internal_name(name);
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen}
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenstatic bool maildir_storage_is_valid_create_name(struct mailbox_list *list,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen const char *name)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen{
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen struct maildir_mailbox_list *mlist = MAILDIR_LIST_CONTEXT(list);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen bool ret = TRUE;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (!mlist->module_ctx.super.is_valid_create_name(list, name))
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return FALSE;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* Don't allow creating mailboxes under cur/new/tmp */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen T_BEGIN {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen const char *const *tmp;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
a3fe8c0c54d87822f4b4f8f0d10caac611861b2bTimo Sirainen for (tmp = t_strsplit(name, "/"); *tmp != NULL; tmp++) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (maildir_is_internal_name(*tmp)) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen ret = FALSE;
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen break;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen } T_END;
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen return ret;
0c22bef8f5b35c645de8affd8746307fc53bd222Timo Sirainen}
0c22bef8f5b35c645de8affd8746307fc53bd222Timo Sirainen
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainenstatic struct mail_storage *maildir_storage_alloc(void)
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen{
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen struct maildir_storage *storage;
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen pool_t pool;
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen pool = pool_alloconly_create("maildir storage", 512+256);
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen storage = p_new(pool, struct maildir_storage, 1);
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen storage->storage = maildir_storage;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen storage->storage.pool = pool;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return &storage->storage;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen}
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenstatic int
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenmaildir_storage_create(struct mail_storage *_storage, struct mail_namespace *ns,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen const char **error_r ATTR_UNUSED)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen struct maildir_storage *storage = (struct maildir_storage *)_storage;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen struct mailbox_list *list = ns->list;
cd2ed64888b42b481cde6bb9548c8520516fa3e9Timo Sirainen const char *dir;
a3fe8c0c54d87822f4b4f8f0d10caac611861b2bTimo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen storage->set = mail_storage_get_driver_settings(_storage);
a3fe8c0c54d87822f4b4f8f0d10caac611861b2bTimo Sirainen
a3fe8c0c54d87822f4b4f8f0d10caac611861b2bTimo Sirainen storage->maildir_list_ext_id = (uint32_t)-1;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen storage->temp_prefix = mailbox_list_get_temp_prefix(list);
e6b4168ba670d9e51ea7877661def039ae6b53c3Timo Sirainen
e6b4168ba670d9e51ea7877661def039ae6b53c3Timo Sirainen if (list->set.control_dir == NULL && list->set.inbox_path == NULL &&
e6b4168ba670d9e51ea7877661def039ae6b53c3Timo Sirainen (ns->flags & NAMESPACE_FLAG_INBOX) != 0) {
e6b4168ba670d9e51ea7877661def039ae6b53c3Timo Sirainen /* put the temp files into tmp/ directory preferrably */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen storage->temp_prefix = p_strconcat(_storage->pool, "tmp/",
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen storage->temp_prefix, NULL);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen dir = mailbox_list_get_path(list, NULL,
01230de017cd273de41143d88e9c18df1243ae8aTimo Sirainen MAILBOX_LIST_PATH_TYPE_DIR);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen } else {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* control dir should also be writable */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen dir = mailbox_list_get_path(list, NULL,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen MAILBOX_LIST_PATH_TYPE_CONTROL);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen _storage->temp_path_prefix = p_strconcat(_storage->pool, dir, "/",
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen storage->temp_prefix, NULL);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return 0;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenstatic void maildir_storage_get_list_settings(const struct mail_namespace *ns,
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen struct mailbox_list_settings *set)
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen{
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen if (set->layout == NULL)
7487ff578435377bbeefffdbfb78ca09ed1292dfTimo Sirainen set->layout = MAILBOX_LIST_NAME_MAILDIRPLUSPLUS;
7487ff578435377bbeefffdbfb78ca09ed1292dfTimo Sirainen if (set->subscription_fname == NULL)
7487ff578435377bbeefffdbfb78ca09ed1292dfTimo Sirainen set->subscription_fname = MAILDIR_SUBSCRIPTION_FILE_NAME;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (set->dir_guid_fname == NULL)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen set->dir_guid_fname = MAILDIR_DIR_GUID_FILE_NAME;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (set->inbox_path == NULL &&
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen (strcmp(set->layout, MAILBOX_LIST_NAME_MAILDIRPLUSPLUS) == 0 ||
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen strcmp(set->layout, MAILBOX_LIST_NAME_FS) == 0) &&
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen (ns->flags & NAMESPACE_FLAG_INBOX) != 0) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* Maildir++ INBOX is the Maildir base itself */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen set->inbox_path = set->root_dir;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen}
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenstatic const char *
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenmaildir_storage_find_root_dir(const struct mail_namespace *ns)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen{
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen bool debug = ns->mail_set->mail_debug;
578ef2538ccf42e2a48234c24a8b709397101d88Timo Sirainen const char *home, *path;
578ef2538ccf42e2a48234c24a8b709397101d88Timo Sirainen
578ef2538ccf42e2a48234c24a8b709397101d88Timo Sirainen /* we'll need to figure out the maildir location ourself.
578ef2538ccf42e2a48234c24a8b709397101d88Timo Sirainen It's ~/Maildir unless we are chrooted. */
578ef2538ccf42e2a48234c24a8b709397101d88Timo Sirainen if (mail_user_get_home(ns->user, &home) > 0) {
578ef2538ccf42e2a48234c24a8b709397101d88Timo Sirainen path = t_strconcat(home, "/Maildir", NULL);
578ef2538ccf42e2a48234c24a8b709397101d88Timo Sirainen if (access(path, R_OK|W_OK|X_OK) == 0) {
578ef2538ccf42e2a48234c24a8b709397101d88Timo Sirainen if (debug)
578ef2538ccf42e2a48234c24a8b709397101d88Timo Sirainen i_info("maildir: root exists (%s)", path);
578ef2538ccf42e2a48234c24a8b709397101d88Timo Sirainen return path;
578ef2538ccf42e2a48234c24a8b709397101d88Timo Sirainen }
578ef2538ccf42e2a48234c24a8b709397101d88Timo Sirainen if (debug)
e0740628f6ca05f4bc79a9d8a90b650f4d38d4d0Timo Sirainen i_info("maildir: access(%s, rwx): failed: %m", path);
e0740628f6ca05f4bc79a9d8a90b650f4d38d4d0Timo Sirainen } else {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (debug)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen i_info("maildir: Home directory not set");
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (access("/cur", R_OK|W_OK|X_OK) == 0) {
c6335901c67a4c9365319190a111a2168f3b06f5Timo Sirainen if (debug)
c6335901c67a4c9365319190a111a2168f3b06f5Timo Sirainen i_info("maildir: /cur exists, assuming chroot");
6d2b3ce2c6ef62334985ece4f0ab8b154e0e9560Timo Sirainen return "/";
6d2b3ce2c6ef62334985ece4f0ab8b154e0e9560Timo Sirainen }
6d2b3ce2c6ef62334985ece4f0ab8b154e0e9560Timo Sirainen }
6d2b3ce2c6ef62334985ece4f0ab8b154e0e9560Timo Sirainen return NULL;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenstatic bool maildir_storage_autodetect(const struct mail_namespace *ns,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen struct mailbox_list_settings *set)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen{
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen bool debug = ns->mail_set->mail_debug;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen struct stat st;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen const char *path, *root_dir;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (set->root_dir != NULL)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen root_dir = set->root_dir;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen else {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen root_dir = maildir_storage_find_root_dir(ns);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (root_dir == NULL) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (debug)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen i_info("maildir: couldn't find root dir");
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return FALSE;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen path = t_strconcat(root_dir, "/cur", NULL);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (stat(path, &st) < 0) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (debug)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen i_info("maildir autodetect: stat(%s) failed: %m", path);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return FALSE;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (!S_ISDIR(st.st_mode)) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (debug)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen i_info("maildir autodetect: %s not a directory", path);
f5e1d3d6b34ec152aa1ff15c7bd3d3552e9227eaTimo Sirainen return FALSE;
f5e1d3d6b34ec152aa1ff15c7bd3d3552e9227eaTimo Sirainen }
f5e1d3d6b34ec152aa1ff15c7bd3d3552e9227eaTimo Sirainen
f5e1d3d6b34ec152aa1ff15c7bd3d3552e9227eaTimo Sirainen set->root_dir = root_dir;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen maildir_storage_get_list_settings(ns, set);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return TRUE;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen}
3f603ef00e35fca21605afa0ad8d76e94fee2b96Timo Sirainen
3f603ef00e35fca21605afa0ad8d76e94fee2b96Timo Sirainenstatic int
3f603ef00e35fca21605afa0ad8d76e94fee2b96Timo Sirainenmkdir_verify(struct mail_storage *storage, struct mail_namespace *ns,
3f603ef00e35fca21605afa0ad8d76e94fee2b96Timo Sirainen const char *dir, mode_t mode, gid_t gid, const char *gid_origin,
3f603ef00e35fca21605afa0ad8d76e94fee2b96Timo Sirainen bool verify)
3f603ef00e35fca21605afa0ad8d76e94fee2b96Timo Sirainen{
86791365b10f45982c88e70f2eb94fd6c3fea151Timo Sirainen struct stat st;
86791365b10f45982c88e70f2eb94fd6c3fea151Timo Sirainen
86791365b10f45982c88e70f2eb94fd6c3fea151Timo Sirainen if (verify) {
86791365b10f45982c88e70f2eb94fd6c3fea151Timo Sirainen if (stat(dir, &st) == 0)
86791365b10f45982c88e70f2eb94fd6c3fea151Timo Sirainen return 0;
86791365b10f45982c88e70f2eb94fd6c3fea151Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (errno != ENOENT) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen mail_storage_set_critical(storage,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen "stat(%s) failed: %m", dir);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return -1;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (mkdir_parents_chgrp(dir, mode, gid, gid_origin) == 0)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return 0;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (errno == EEXIST) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (verify)
d39a04db2f4d0599cb9b5f03a9aa10a3c234453cTimo Sirainen return 0;
d39a04db2f4d0599cb9b5f03a9aa10a3c234453cTimo Sirainen mail_storage_set_error(storage, MAIL_ERROR_EXISTS,
d39a04db2f4d0599cb9b5f03a9aa10a3c234453cTimo Sirainen "Mailbox already exists");
d39a04db2f4d0599cb9b5f03a9aa10a3c234453cTimo Sirainen } else if (errno == ENOENT) {
d39a04db2f4d0599cb9b5f03a9aa10a3c234453cTimo Sirainen mail_storage_set_error(storage, MAIL_ERROR_NOTFOUND,
17fe695b985e9d6e9dc39c05b24e6b3c3b7e1ba1Timo Sirainen "Mailbox was deleted while it was being created");
047c00cd3f7f403672f81569413669238df8c15aTimo Sirainen } else if (errno == EACCES) {
17fe695b985e9d6e9dc39c05b24e6b3c3b7e1ba1Timo Sirainen if (ns->type == NAMESPACE_SHARED) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* shared namespace, don't log permission errors */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen mail_storage_set_error(storage, MAIL_ERROR_PERM,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen MAIL_ERRSTR_NO_PERMISSION);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return -1;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen mail_storage_set_critical(storage, "%s",
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen mail_error_create_eacces_msg("mkdir", dir));
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen } else {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen mail_storage_set_critical(storage,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen "mkdir(%s) failed: %m", dir);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return -1;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen}
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d7eb4104707c60ca7e9d0228b37c5133476907bTimo Sirainenstatic int maildir_check_tmp(struct mail_storage *storage, const char *dir)
8d7eb4104707c60ca7e9d0228b37c5133476907bTimo Sirainen{
86791365b10f45982c88e70f2eb94fd6c3fea151Timo Sirainen const char *path;
8d7eb4104707c60ca7e9d0228b37c5133476907bTimo Sirainen struct stat st;
86791365b10f45982c88e70f2eb94fd6c3fea151Timo Sirainen
86791365b10f45982c88e70f2eb94fd6c3fea151Timo Sirainen /* if tmp/ directory exists, we need to clean it up once in a while */
86791365b10f45982c88e70f2eb94fd6c3fea151Timo Sirainen path = t_strconcat(dir, "/tmp", NULL);
86791365b10f45982c88e70f2eb94fd6c3fea151Timo Sirainen if (stat(path, &st) < 0) {
86791365b10f45982c88e70f2eb94fd6c3fea151Timo Sirainen if (errno == ENOENT)
86791365b10f45982c88e70f2eb94fd6c3fea151Timo Sirainen return 0;
86791365b10f45982c88e70f2eb94fd6c3fea151Timo Sirainen if (errno == EACCES) {
86791365b10f45982c88e70f2eb94fd6c3fea151Timo Sirainen mail_storage_set_critical(storage, "%s",
86791365b10f45982c88e70f2eb94fd6c3fea151Timo Sirainen mail_error_eacces_msg("stat", path));
86791365b10f45982c88e70f2eb94fd6c3fea151Timo Sirainen return -1;
86791365b10f45982c88e70f2eb94fd6c3fea151Timo Sirainen }
8d7eb4104707c60ca7e9d0228b37c5133476907bTimo Sirainen mail_storage_set_critical(storage, "stat(%s) failed: %m", path);
8d7eb4104707c60ca7e9d0228b37c5133476907bTimo Sirainen return -1;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (st.st_atime > st.st_ctime + MAILDIR_TMP_DELETE_SECS) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* the directory should be empty. we won't do anything
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen until ctime changes. */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen } else if (st.st_atime < ioloop_time - MAILDIR_TMP_SCAN_SECS) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* time to scan */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen (void)unlink_old_files(path, "",
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen ioloop_time - MAILDIR_TMP_DELETE_SECS);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return 1;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
8d7eb4104707c60ca7e9d0228b37c5133476907bTimo Sirainen/* create or fix maildir, ignore if it already exists */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenstatic int
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainencreate_maildir(struct mail_storage *storage, struct mail_namespace *ns,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen const char *dir, mode_t mode, gid_t gid, const char *gid_origin,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen bool verify)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen const char *path;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen unsigned int i;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen int ret;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (!verify) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen ret = maildir_check_tmp(storage, dir);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (ret > 0) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen mail_storage_set_error(storage,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen MAIL_ERROR_EXISTS, "Mailbox already exists");
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return -1;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (ret < 0)
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen return -1;
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen }
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen for (i = 0; i < N_ELEMENTS(maildir_subdirs); i++) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen path = t_strconcat(dir, "/", maildir_subdirs[i], NULL);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (mkdir_verify(storage, ns, path, mode, gid,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen gid_origin, verify) < 0)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return -1;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return 0;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenstatic void maildir_lock_touch_timeout(struct maildir_mailbox *mbox)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen (void)maildir_uidlist_lock_touch(mbox->uidlist);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenstatic mode_t get_dir_mode(mode_t mode)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* add the execute bit if either read or write bit is set */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if ((mode & 0600) != 0) mode |= 0100;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if ((mode & 0060) != 0) mode |= 0010;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if ((mode & 0006) != 0) mode |= 0001;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return mode;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
788f275469ad9ed530e440d6690d0e4381a323b2Timo Sirainen
788f275469ad9ed530e440d6690d0e4381a323b2Timo Sirainenstatic struct mailbox *
788f275469ad9ed530e440d6690d0e4381a323b2Timo Sirainenmaildir_mailbox_alloc(struct mail_storage *storage, struct mailbox_list *list,
788f275469ad9ed530e440d6690d0e4381a323b2Timo Sirainen const char *name, struct istream *input,
788f275469ad9ed530e440d6690d0e4381a323b2Timo Sirainen enum mailbox_flags flags)
788f275469ad9ed530e440d6690d0e4381a323b2Timo Sirainen{
788f275469ad9ed530e440d6690d0e4381a323b2Timo Sirainen struct maildir_mailbox *mbox;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen pool_t pool;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen pool = pool_alloconly_create("maildir mailbox", 1024+512);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen mbox = p_new(pool, struct maildir_mailbox, 1);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen mbox->ibox.box = maildir_mailbox;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen mbox->ibox.box.pool = pool;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen mbox->ibox.box.storage = storage;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen mbox->ibox.box.list = list;
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen mbox->ibox.mail_vfuncs = &maildir_mail_vfuncs;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen mbox->ibox.save_commit_pre = maildir_transaction_save_commit_pre;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen mbox->ibox.save_commit_post = maildir_transaction_save_commit_post;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen mbox->ibox.save_rollback = maildir_transaction_save_rollback;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen index_storage_mailbox_alloc(&mbox->ibox, name, input, flags,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen MAILDIR_INDEX_PREFIX);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen mbox->storage = (struct maildir_storage *)storage;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen mbox->maildir_ext_id =
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen mail_index_ext_register(mbox->ibox.index, "maildir",
9240d99920783c56405dda74a1f6c7ff1ebed8e6Timo Sirainen sizeof(mbox->maildir_hdr), 0, 0);
9240d99920783c56405dda74a1f6c7ff1ebed8e6Timo Sirainen mbox->uidlist = maildir_uidlist_init(mbox);
9240d99920783c56405dda74a1f6c7ff1ebed8e6Timo Sirainen mbox->keywords = maildir_keywords_init(mbox);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return &mbox->ibox.box;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen}
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenstatic int maildir_mailbox_open_existing(struct mailbox *box)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen{
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen struct maildir_mailbox *mbox = (struct maildir_mailbox *)box;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen struct stat st;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen const char *shared_path;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* for shared mailboxes get the create mode from the
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen permissions of dovecot-shared file. */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen shared_path = t_strconcat(box->path, "/dovecot-shared", NULL);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (stat(shared_path, &st) == 0) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if ((st.st_mode & S_ISGID) != 0 ||
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen (st.st_mode & 0060) == 0) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* Ignore GID */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen st.st_gid = (gid_t)-1;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen mail_index_set_permissions(mbox->ibox.index,
9240d99920783c56405dda74a1f6c7ff1ebed8e6Timo Sirainen st.st_mode & 0666, st.st_gid,
9240d99920783c56405dda74a1f6c7ff1ebed8e6Timo Sirainen shared_path);
9240d99920783c56405dda74a1f6c7ff1ebed8e6Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen box->file_create_mode = st.st_mode & 0666;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen box->dir_create_mode = get_dir_mode(st.st_mode & 0666);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen box->file_create_gid = st.st_gid;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen mbox->ibox.box.file_create_gid_origin =
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen p_strdup(box->pool, shared_path);
885e1b36da370a674c0fd3b85db53740d7dcbd9bTimo Sirainen box->private_flags_mask = MAIL_SEEN;
885e1b36da370a674c0fd3b85db53740d7dcbd9bTimo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if ((box->flags & MAILBOX_FLAG_KEEP_LOCKED) != 0) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (maildir_uidlist_lock(mbox->uidlist) <= 0)
885e1b36da370a674c0fd3b85db53740d7dcbd9bTimo Sirainen return -1;
885e1b36da370a674c0fd3b85db53740d7dcbd9bTimo Sirainen mbox->keep_lock_to = timeout_add(MAILDIR_LOCK_TOUCH_SECS * 1000,
885e1b36da370a674c0fd3b85db53740d7dcbd9bTimo Sirainen maildir_lock_touch_timeout,
885e1b36da370a674c0fd3b85db53740d7dcbd9bTimo Sirainen mbox);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
885e1b36da370a674c0fd3b85db53740d7dcbd9bTimo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (access(t_strconcat(box->path, "/cur", NULL), W_OK) < 0 &&
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen errno == EACCES)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen mbox->ibox.backend_readonly = TRUE;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return index_storage_mailbox_open(box);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenstatic int maildir_mailbox_open(struct mailbox *box)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen struct stat st;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen const char *gid_origin;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen mode_t mode;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen gid_t gid;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen int ret;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen bool inbox;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (box->input != NULL) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen mail_storage_set_critical(box->storage,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen "Maildir doesn't support streamed mailboxes");
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return -1;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen inbox = strcmp(box->name, "INBOX") == 0 &&
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen (box->list->ns->flags & NAMESPACE_FLAG_INBOX) != 0;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* begin by checking if tmp/ directory exists and if it should be
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen cleaned up. */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen ret = maildir_check_tmp(box->storage, box->path);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (ret > 0) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* exists */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return maildir_mailbox_open_existing(box);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (ret < 0)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return -1;
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen /* tmp/ directory doesn't exist. does the maildir? */
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen if (inbox || (*box->name != '\0' && stat(box->path, &st) == 0)) {
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen /* yes, we'll need to create the missing dirs */
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen mailbox_list_get_dir_permissions(box->list, box->name,
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen &mode, &gid, &gid_origin);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (create_maildir(box->storage, box->list->ns, box->path,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen mode, gid, gid_origin, TRUE) < 0)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return -1;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return maildir_mailbox_open_existing(box);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen } else if (*box->name == '\0' || errno == ENOENT) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen mail_storage_set_error(box->storage, MAIL_ERROR_NOTFOUND,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen T_MAIL_ERR_MAILBOX_NOT_FOUND(box->name));
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return -1;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen } else {
b2d562f9c7fd13f9a16e9b3bcee904630b80b1feTimo Sirainen mail_storage_set_critical(box->storage,
b2d562f9c7fd13f9a16e9b3bcee904630b80b1feTimo Sirainen "stat(%s) failed: %m", box->path);
b2d562f9c7fd13f9a16e9b3bcee904630b80b1feTimo Sirainen return -1;
b2d562f9c7fd13f9a16e9b3bcee904630b80b1feTimo Sirainen }
b2d562f9c7fd13f9a16e9b3bcee904630b80b1feTimo Sirainen}
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenstatic int
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenmaildir_create_shared(struct mail_storage *storage, struct mail_namespace *ns,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen const char *dir, mode_t mode, gid_t gid,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen const char *gid_origin)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen const char *path;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen mode_t old_mask;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen int fd;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* add the execute bit if either read or write bit is set */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if ((mode & 0600) != 0) mode |= 0100;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if ((mode & 0060) != 0) mode |= 0010;
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen if ((mode & 0006) != 0) mode |= 0001;
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen if (create_maildir(storage, ns, dir, mode, gid, gid_origin, FALSE) < 0)
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen return -1;
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen old_mask = umask(0777 ^ mode);
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen path = t_strconcat(dir, "/dovecot-shared", NULL);
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen fd = open(path, O_WRONLY | O_CREAT, mode & 0666);
1bea4b9c24fbe2b457950c09cf072292a6701cffTimo Sirainen umask(old_mask);
1bea4b9c24fbe2b457950c09cf072292a6701cffTimo Sirainen
1bea4b9c24fbe2b457950c09cf072292a6701cffTimo Sirainen if (fd == -1) {
1bea4b9c24fbe2b457950c09cf072292a6701cffTimo Sirainen mail_storage_set_critical(storage, "open(%s) failed: %m", path);
1bea4b9c24fbe2b457950c09cf072292a6701cffTimo Sirainen return -1;
1bea4b9c24fbe2b457950c09cf072292a6701cffTimo Sirainen }
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen
1bea4b9c24fbe2b457950c09cf072292a6701cffTimo Sirainen if (fchown(fd, (uid_t)-1, gid) < 0) {
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen if (errno == EPERM) {
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen mail_storage_set_critical(storage, "%s",
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen eperm_error_get_chgrp("fchown", path,
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen gid, gid_origin));
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen } else {
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen mail_storage_set_critical(storage,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen "fchown(%s) failed: %m", path);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
2ac0a22865272cb4311a1bd09eb69b475625b3ebTimo Sirainen }
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen (void)close(fd);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return 0;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenstatic int
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenmaildir_mailbox_update(struct mailbox *box, const struct mailbox_update *update)
885e1b36da370a674c0fd3b85db53740d7dcbd9bTimo Sirainen{
885e1b36da370a674c0fd3b85db53740d7dcbd9bTimo Sirainen struct maildir_mailbox *mbox = (struct maildir_mailbox *)box;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen struct maildir_uidlist *uidlist = mbox->uidlist;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen int ret;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (maildir_uidlist_lock(uidlist) <= 0)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return -1;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (!mail_guid_128_is_empty(update->mailbox_guid))
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen maildir_uidlist_set_mailbox_guid(uidlist, update->mailbox_guid);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (update->uid_validity != 0)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen maildir_uidlist_set_uid_validity(uidlist, update->uid_validity);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (update->min_next_uid != 0) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen maildir_uidlist_set_next_uid(uidlist, update->min_next_uid,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen FALSE);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen ret = maildir_uidlist_update(uidlist);
c668292359474a4aa8c608b30a858337fa3fc813Timo Sirainen if (ret == 0)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen ret = index_storage_mailbox_update(box, update);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen maildir_uidlist_unlock(uidlist);
c668292359474a4aa8c608b30a858337fa3fc813Timo Sirainen return ret;
c668292359474a4aa8c608b30a858337fa3fc813Timo Sirainen}
c668292359474a4aa8c608b30a858337fa3fc813Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenstatic int
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenmaildir_mailbox_create(struct mailbox *box, const struct mailbox_update *update,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen bool directory)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen struct stat st;
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen const char *path, *root_dir, *shared_path, *gid_origin;
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen mode_t old_mask;
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen int fd;
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen path = mailbox_list_get_path(box->list, box->name,
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen MAILBOX_LIST_PATH_TYPE_MAILBOX);
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen root_dir = mailbox_list_get_path(box->list, NULL,
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen MAILBOX_LIST_PATH_TYPE_MAILBOX);
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen /* if dovecot-shared exists in the root dir, create the mailbox using
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen its permissions and gid, and copy the dovecot-shared inside it. */
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen shared_path = t_strconcat(root_dir, "/dovecot-shared", NULL);
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen if (stat(shared_path, &st) == 0) {
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen gid_origin = shared_path;
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen if (maildir_create_shared(box->storage, box->list->ns, path,
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen st.st_mode & 0666, st.st_gid,
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen gid_origin) < 0)
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen return -1;
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen } else {
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen mailbox_list_get_dir_permissions(box->list, NULL, &st.st_mode,
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen &st.st_gid, &gid_origin);
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen if (create_maildir(box->storage, box->list->ns, path,
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen st.st_mode, st.st_gid, gid_origin,
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen FALSE) < 0)
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen return -1;
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen }
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen /* Maildir++ spec wants that maildirfolder named file is created for
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen all subfolders. */
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen path = t_strconcat(path, "/" MAILDIR_SUBFOLDER_FILENAME, NULL);
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen old_mask = umask(0777 ^ (st.st_mode & 0666));
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen fd = open(path, O_CREAT | O_WRONLY, 0666);
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen umask(old_mask);
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen if (fd != -1) {
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen /* if dovecot-shared exists, use the same group */
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen if (st.st_gid == (gid_t)-1) {
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen /* doesn't exist */
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen } else if (fchown(fd, (uid_t)-1, st.st_gid) == 0) {
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen /* ok */
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen } else if (errno == EPERM) {
3ba9a079592f46e94ce846e5aa80e4d479cd5e41Timo Sirainen mail_storage_set_critical(box->storage, "%s",
6a6e3c2538a08cc4880a8db7e0a9a3392122ea04Timo Sirainen eperm_error_get_chgrp("fchown", path,
6a6e3c2538a08cc4880a8db7e0a9a3392122ea04Timo Sirainen st.st_gid, gid_origin));
6a6e3c2538a08cc4880a8db7e0a9a3392122ea04Timo Sirainen } else {
6a6e3c2538a08cc4880a8db7e0a9a3392122ea04Timo Sirainen mail_storage_set_critical(box->storage,
6a6e3c2538a08cc4880a8db7e0a9a3392122ea04Timo Sirainen "fchown(%s) failed: %m", path);
6a6e3c2538a08cc4880a8db7e0a9a3392122ea04Timo Sirainen }
6a6e3c2538a08cc4880a8db7e0a9a3392122ea04Timo Sirainen (void)close(fd);
6a6e3c2538a08cc4880a8db7e0a9a3392122ea04Timo Sirainen } else if (errno == ENOENT) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen mail_storage_set_error(box->storage, MAIL_ERROR_NOTFOUND,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen "Mailbox was deleted while it was being created");
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return -1;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen } else {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen mail_storage_set_critical(box->storage,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen "open(%s, O_CREAT) failed: %m", path);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return directory || update == NULL ? 0 :
6a6e3c2538a08cc4880a8db7e0a9a3392122ea04Timo Sirainen maildir_mailbox_update(box, update);
86791365b10f45982c88e70f2eb94fd6c3fea151Timo Sirainen}
86791365b10f45982c88e70f2eb94fd6c3fea151Timo Sirainen
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainenstatic void
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainenmaildir_storage_get_status(struct mailbox *box, enum mailbox_status_items items,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen struct mailbox_status *status_r)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen struct maildir_mailbox *mbox = (struct maildir_mailbox *)box;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d39a04db2f4d0599cb9b5f03a9aa10a3c234453cTimo Sirainen index_storage_get_status(box, items, status_r);
d39a04db2f4d0599cb9b5f03a9aa10a3c234453cTimo Sirainen if ((items & STATUS_GUID) != 0) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen (void)maildir_uidlist_get_mailbox_guid(mbox->uidlist,
c99fe55d4535d839a6ad0735c4719e076a1adb2cTimo Sirainen status_r->mailbox_guid);
c99fe55d4535d839a6ad0735c4719e076a1adb2cTimo Sirainen }
c99fe55d4535d839a6ad0735c4719e076a1adb2cTimo Sirainen}
c99fe55d4535d839a6ad0735c4719e076a1adb2cTimo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenstatic const char *
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenmaildir_get_unlink_dest(struct mailbox_list *list, const char *name)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen{
6ed1e82824590b514201d9db84ba96bdfc832dd5Timo Sirainen const char *root_dir;
578ef2538ccf42e2a48234c24a8b709397101d88Timo Sirainen char sep;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (list->mail_set->mail_full_filesystem_access &&
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen (*name == '/' || *name == '~'))
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return NULL;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (strcmp(mailbox_list_get_driver_name(list),
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen MAILBOX_LIST_NAME_MAILDIRPLUSPLUS) != 0) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* Not maildir++ driver. Don't use this trick. */
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen return NULL;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
3ba9a079592f46e94ce846e5aa80e4d479cd5e41Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen root_dir = mailbox_list_get_path(list, NULL,
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen MAILBOX_LIST_PATH_TYPE_DIR);
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen sep = mailbox_list_get_hierarchy_sep(list);
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen return t_strdup_printf("%s/%c%c"MAILDIR_UNLINK_DIRNAME, root_dir,
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen sep, sep);
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen}
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainenstatic int
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainenmaildir_delete_nonrecursive(struct mailbox_list *list, const char *path,
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen const char *name)
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen{
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen DIR *dir;
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen struct dirent *d;
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen string_t *full_path;
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen unsigned int dir_len;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen bool unlinked_something = FALSE;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen dir = opendir(path);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (dir == NULL) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (errno == ENOENT) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen mailbox_list_set_error(list, MAIL_ERROR_NOTFOUND,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen T_MAIL_ERR_MAILBOX_NOT_FOUND(name));
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen } else {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen mailbox_list_set_critical(list,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen "opendir(%s) failed: %m", path);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen return -1;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen full_path = t_str_new(256);
2ac0a22865272cb4311a1bd09eb69b475625b3ebTimo Sirainen str_append(full_path, path);
89237470342ea6d4bbdf4cff9764037cfb3f6f45Timo Sirainen str_append_c(full_path, '/');
e3540e734a79fd4f971652925079c2e26a4b5524Timo Sirainen dir_len = str_len(full_path);
89237470342ea6d4bbdf4cff9764037cfb3f6f45Timo Sirainen
89237470342ea6d4bbdf4cff9764037cfb3f6f45Timo Sirainen errno = 0;
89237470342ea6d4bbdf4cff9764037cfb3f6f45Timo Sirainen while ((d = readdir(dir)) != NULL) {
89237470342ea6d4bbdf4cff9764037cfb3f6f45Timo Sirainen if (d->d_name[0] == '.') {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* skip . and .. */
7487ff578435377bbeefffdbfb78ca09ed1292dfTimo Sirainen if (d->d_name[1] == '\0')
e4eb49e29197c6783ec93b868100394e189f4e0cTimo Sirainen continue;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (d->d_name[1] == '.' && d->d_name[2] == '\0')
3ba9a079592f46e94ce846e5aa80e4d479cd5e41Timo Sirainen continue;
3ba9a079592f46e94ce846e5aa80e4d479cd5e41Timo Sirainen }
3ba9a079592f46e94ce846e5aa80e4d479cd5e41Timo Sirainen
3ba9a079592f46e94ce846e5aa80e4d479cd5e41Timo Sirainen str_truncate(full_path, dir_len);
3ba9a079592f46e94ce846e5aa80e4d479cd5e41Timo Sirainen str_append(full_path, d->d_name);
3ba9a079592f46e94ce846e5aa80e4d479cd5e41Timo Sirainen
3ba9a079592f46e94ce846e5aa80e4d479cd5e41Timo Sirainen if (maildir_is_internal_name(d->d_name)) {
3ba9a079592f46e94ce846e5aa80e4d479cd5e41Timo Sirainen if (unlink_directory(str_c(full_path), TRUE) < 0) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen mailbox_list_set_critical(list,
6a6e3c2538a08cc4880a8db7e0a9a3392122ea04Timo Sirainen "unlink_directory(%s) failed: %m",
6a6e3c2538a08cc4880a8db7e0a9a3392122ea04Timo Sirainen str_c(full_path));
3ba9a079592f46e94ce846e5aa80e4d479cd5e41Timo Sirainen } else {
6a6e3c2538a08cc4880a8db7e0a9a3392122ea04Timo Sirainen unlinked_something = TRUE;
6a6e3c2538a08cc4880a8db7e0a9a3392122ea04Timo Sirainen }
6a6e3c2538a08cc4880a8db7e0a9a3392122ea04Timo Sirainen continue;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
2ac0a22865272cb4311a1bd09eb69b475625b3ebTimo Sirainen /* trying to unlink() a directory gives either EPERM or EISDIR
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen (non-POSIX). it doesn't really work anywhere in practise,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen so don't bother stat()ing the file first */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (unlink(str_c(full_path)) == 0)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen unlinked_something = TRUE;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen else if (errno != ENOENT && errno != EISDIR && errno != EPERM) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen mailbox_list_set_critical(list,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen "unlink_directory(%s) failed: %m",
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen str_c(full_path));
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (closedir(dir) < 0) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen mailbox_list_set_critical(list, "closedir(%s) failed: %m",
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen path);
7487ff578435377bbeefffdbfb78ca09ed1292dfTimo Sirainen }
7487ff578435377bbeefffdbfb78ca09ed1292dfTimo Sirainen
7487ff578435377bbeefffdbfb78ca09ed1292dfTimo Sirainen if (rmdir(path) == 0)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen unlinked_something = TRUE;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen else if (errno != ENOENT && errno != ENOTEMPTY) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen mailbox_list_set_critical(list, "rmdir(%s) failed: %m", path);
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen return -1;
2ac0a22865272cb4311a1bd09eb69b475625b3ebTimo Sirainen }
2ac0a22865272cb4311a1bd09eb69b475625b3ebTimo Sirainen
2ac0a22865272cb4311a1bd09eb69b475625b3ebTimo Sirainen if (!unlinked_something) {
2ac0a22865272cb4311a1bd09eb69b475625b3ebTimo Sirainen mailbox_list_set_error(list, MAIL_ERROR_NOTFOUND,
2ac0a22865272cb4311a1bd09eb69b475625b3ebTimo Sirainen t_strdup_printf("Directory %s isn't empty, "
2ac0a22865272cb4311a1bd09eb69b475625b3ebTimo Sirainen "can't delete it.", name));
2ac0a22865272cb4311a1bd09eb69b475625b3ebTimo Sirainen return -1;
2ac0a22865272cb4311a1bd09eb69b475625b3ebTimo Sirainen }
2ac0a22865272cb4311a1bd09eb69b475625b3ebTimo Sirainen return 0;
89237470342ea6d4bbdf4cff9764037cfb3f6f45Timo Sirainen}
2ac0a22865272cb4311a1bd09eb69b475625b3ebTimo Sirainen
2ac0a22865272cb4311a1bd09eb69b475625b3ebTimo Sirainenstatic int
2ac0a22865272cb4311a1bd09eb69b475625b3ebTimo Sirainenmaildir_delete_with_trash(struct mailbox_list *list, const char *src,
2ac0a22865272cb4311a1bd09eb69b475625b3ebTimo Sirainen const char *dest, const char *name)
2ac0a22865272cb4311a1bd09eb69b475625b3ebTimo Sirainen{
2ac0a22865272cb4311a1bd09eb69b475625b3ebTimo Sirainen unsigned int count;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* rename the .maildir into ..DOVECOT-TRASH which atomically
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen marks it as being deleted. If we die before deleting the
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen ..DOVECOT-TRASH directory, it gets deleted the next time
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen mailbox listing sees it. */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen count = 0;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen while (rename(src, dest) < 0) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (errno == ENOENT) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* it was just deleted under us by
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen another process */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen mailbox_list_set_error(list, MAIL_ERROR_NOTFOUND,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen T_MAIL_ERR_MAILBOX_NOT_FOUND(name));
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return -1;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (!EDESTDIREXISTS(errno)) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen mailbox_list_set_critical(list,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen "rename(%s, %s) failed: %m", src, dest);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return -1;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* already existed, delete it and try again */
3ba9a079592f46e94ce846e5aa80e4d479cd5e41Timo Sirainen if (unlink_directory(dest, TRUE) < 0 &&
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen (errno != ENOTEMPTY || count >= 5)) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen mailbox_list_set_critical(list,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen "unlink_directory(%s) failed: %m", dest);
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen return -1;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen count++;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (unlink_directory(dest, TRUE) < 0 && errno != ENOTEMPTY) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen mailbox_list_set_critical(list,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen "unlink_directory(%s) failed: %m", dest);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* it's already renamed to ..dir, which means it's
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen deleted as far as the client is concerned. Report
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen success. */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return 0;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenstatic void mailbox_get_guid(struct mailbox_list *list, const char *name,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen uint8_t mailbox_guid[MAIL_GUID_128_SIZE])
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen struct mailbox *box;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen struct mailbox_status status;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen box = mailbox_alloc(list, name, NULL, MAILBOX_FLAG_KEEP_RECENT);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (mailbox_open(box) < 0)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen memset(mailbox_guid, 0, MAIL_GUID_128_SIZE);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen else {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen mailbox_get_status(box, STATUS_GUID, &status);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen memcpy(mailbox_guid, status.mailbox_guid, MAIL_GUID_128_SIZE);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen mailbox_close(&box);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
static int
maildir_list_delete_mailbox(struct mailbox_list *list, const char *name)
{
union mailbox_list_module_context *mlist = MAILDIR_LIST_CONTEXT(list);
uint8_t mailbox_guid[MAIL_GUID_128_SIZE];
uint8_t dir_guid[MAIL_GUID_128_SIZE];
struct stat st;
const char *src, *dest, *base;
int ret;
mailbox_get_guid(list, name, mailbox_guid);
(void)mailbox_list_get_guid(list, name, dir_guid);
/* Make sure the indexes are closed before trying to delete the
directory that contains them. It can still fail with some NFS
implementations if indexes are opened by another session, but
that can't really be helped. */
index_storage_destroy_unrefed();
/* delete the index and control directories */
if (mlist->super.delete_mailbox(list, name) < 0)
return -1;
/* check if the mailbox actually exists */
src = mailbox_list_get_path(list, name, MAILBOX_LIST_PATH_TYPE_MAILBOX);
if (lstat(src, &st) != 0 && errno == ENOENT) {
mailbox_list_set_error(list, MAIL_ERROR_NOTFOUND,
T_MAIL_ERR_MAILBOX_NOT_FOUND(name));
return -1;
}
if (!S_ISDIR(st.st_mode)) {
/* a symlink most likely */
if (unlink(src) < 0 && errno != ENOENT) {
mailbox_list_set_critical(list,
"unlink(%s) failed: %m", src);
return -1;
}
return 0;
}
if (strcmp(name, "INBOX") == 0) {
/* we shouldn't get this far if this is the actual INBOX.
more likely we're just deleting a namespace/INBOX.
be anyway sure that we don't accidentally delete the entire
maildir (INBOX explicitly configured to maildir root). */
base = mailbox_list_get_path(list, NULL,
MAILBOX_LIST_PATH_TYPE_MAILBOX);
if (strcmp(base, src) == 0) {
mailbox_list_set_error(list, MAIL_ERROR_NOTPOSSIBLE,
"INBOX can't be deleted.");
return -1;
}
}
dest = maildir_get_unlink_dest(list, name);
if (dest == NULL) {
/* delete the directory directly without any renaming */
ret = maildir_delete_nonrecursive(list, src, name);
} else {
ret = maildir_delete_with_trash(list, src, dest, name);
}
if (ret == 0) {
mailbox_list_add_change(list, MAILBOX_LOG_RECORD_DELETE_MAILBOX,
mailbox_guid);
mailbox_list_add_change(list, MAILBOX_LOG_RECORD_DELETE_DIR,
dir_guid);
}
return 0;
}
static int
maildir_list_rename_mailbox(struct mailbox_list *oldlist, const char *oldname,
struct mailbox_list *newlist, const char *newname,
bool rename_children)
{
struct maildir_mailbox_list *oldmlist = MAILDIR_LIST_CONTEXT(oldlist);
const char *path1, *path2;
if (strcmp(oldname, "INBOX") == 0) {
/* INBOX often exists as the root ~/Maildir.
We can't rename it then. */
path1 = mailbox_list_get_path(oldlist, oldname,
MAILBOX_LIST_PATH_TYPE_MAILBOX);
path2 = mailbox_list_get_path(oldlist, NULL,
MAILBOX_LIST_PATH_TYPE_MAILBOX);
if (strcmp(path1, path2) == 0) {
mailbox_list_set_error(oldlist, MAIL_ERROR_NOTPOSSIBLE,
"Renaming INBOX isn't supported.");
return -1;
}
}
return oldmlist->module_ctx.super.
rename_mailbox(oldlist, oldname, newlist, newname,
rename_children);
}
static void maildir_mailbox_close(struct mailbox *box)
{
struct maildir_mailbox *mbox = (struct maildir_mailbox *)box;
if (mbox->keep_lock_to != NULL) {
maildir_uidlist_unlock(mbox->uidlist);
timeout_remove(&mbox->keep_lock_to);
}
if (mbox->flags_view != NULL)
mail_index_view_close(&mbox->flags_view);
if (mbox->keywords != NULL)
maildir_keywords_deinit(&mbox->keywords);
maildir_uidlist_deinit(&mbox->uidlist);
index_storage_mailbox_close(box);
}
static void maildir_notify_changes(struct mailbox *box)
{
struct maildir_mailbox *mbox = (struct maildir_mailbox *)box;
if (box->notify_callback == NULL)
index_mailbox_check_remove_all(&mbox->ibox);
else {
index_mailbox_check_add(&mbox->ibox,
t_strconcat(mbox->ibox.box.path, "/new", NULL));
index_mailbox_check_add(&mbox->ibox,
t_strconcat(mbox->ibox.box.path, "/cur", NULL));
}
}
static int
maildir_list_iter_is_mailbox(struct mailbox_list_iterate_context *ctx
ATTR_UNUSED,
const char *dir, const char *fname,
const char *mailbox_name ATTR_UNUSED,
enum mailbox_list_file_type type,
enum mailbox_info_flags *flags)
{
struct stat st, st2;
const char *path, *cur_path;
int ret;
if (maildir_is_internal_name(fname)) {
*flags |= MAILBOX_NONEXISTENT;
return 0;
}
switch (type) {
case MAILBOX_LIST_FILE_TYPE_FILE:
case MAILBOX_LIST_FILE_TYPE_OTHER:
/* non-directories are not */
*flags |= MAILBOX_NOSELECT;
return 0;
case MAILBOX_LIST_FILE_TYPE_DIR:
case MAILBOX_LIST_FILE_TYPE_UNKNOWN:
case MAILBOX_LIST_FILE_TYPE_SYMLINK:
break;
}
path = t_strdup_printf("%s/%s", dir, fname);
if (stat(path, &st) == 0) {
if (!S_ISDIR(st.st_mode)) {
if (strncmp(fname, ".nfs", 4) == 0) {
/* temporary NFS file */
*flags |= MAILBOX_NONEXISTENT;
} else {
*flags |= MAILBOX_NOSELECT |
MAILBOX_NOINFERIORS;
}
return 0;
}
ret = 1;
} else if (errno == ENOENT) {
/* doesn't exist - probably a non-existing subscribed mailbox */
*flags |= MAILBOX_NONEXISTENT;
ret = 0;
} else {
/* non-selectable. probably either access denied, or symlink
destination not found. don't bother logging errors. */
*flags |= MAILBOX_NOSELECT;
ret = 1;
}
if ((*flags & (MAILBOX_NOSELECT | MAILBOX_NONEXISTENT)) == 0) {
/* make sure it's a selectable mailbox */
cur_path = t_strconcat(path, "/cur", NULL);
if (stat(cur_path, &st2) < 0 || !S_ISDIR(st2.st_mode))
*flags |= MAILBOX_NOSELECT;
if (*ctx->list->set.maildir_name == '\0') {
/* now we can figure out based on the link count if we
have child mailboxes or not. for a selectable
mailbox we have 3 more links (cur/, new/ and tmp/)
than non-selectable. */
if ((*flags & MAILBOX_NOSELECT) == 0) {
if (st.st_nlink > 5)
*flags |= MAILBOX_CHILDREN;
else
*flags |= MAILBOX_NOCHILDREN;
} else {
if (st.st_nlink > 2)
*flags |= MAILBOX_CHILDREN;
else
*flags |= MAILBOX_NOCHILDREN;
}
} else {
/* link count 3 may mean either a selectable mailbox
or a non-selectable mailbox with 1 child. */
if (st.st_nlink > 3)
*flags |= MAILBOX_CHILDREN;
else if (st.st_nlink == 3) {
if ((*flags & MAILBOX_NOSELECT) != 0)
*flags |= MAILBOX_CHILDREN;
else
*flags |= MAILBOX_NOCHILDREN;
}
}
}
return ret;
}
static int
maildirplusplus_iter_is_mailbox(struct mailbox_list_iterate_context *ctx,
const char *dir, const char *fname,
const char *mailbox_name ATTR_UNUSED,
enum mailbox_list_file_type type,
enum mailbox_info_flags *flags)
{
struct maildir_mailbox_list *mlist = MAILDIR_LIST_CONTEXT(ctx->list);
int ret;
if (fname[1] == mailbox_list_get_hierarchy_sep(ctx->list) &&
strcmp(fname+2, MAILDIR_UNLINK_DIRNAME) == 0) {
const char *path;
struct stat st;
/* this directory is in the middle of being deleted,
or the process trying to delete it had died.
delete it ourself if it's been there longer than
one hour. */
path = t_strdup_printf("%s/%s", dir, fname);
if (stat(path, &st) == 0 &&
st.st_mtime < ioloop_time - 3600)
(void)unlink_directory(path, TRUE);
*flags |= MAILBOX_NONEXISTENT;
return 0;
}
switch (type) {
case MAILBOX_LIST_FILE_TYPE_DIR:
/* all directories are valid maildirs */
return 1;
case MAILBOX_LIST_FILE_TYPE_FILE:
case MAILBOX_LIST_FILE_TYPE_OTHER:
/* non-directories are not */
*flags |= MAILBOX_NOSELECT;
return 0;
case MAILBOX_LIST_FILE_TYPE_UNKNOWN:
case MAILBOX_LIST_FILE_TYPE_SYMLINK:
/* need to check with stat() to be sure */
break;
}
/* Check files beginning with .nfs always because they may be
temporary files created by the kernel */
if (mlist->set->maildir_stat_dirs || *fname == '\0' ||
strncmp(fname, ".nfs", 4) == 0) {
const char *path;
struct stat st;
/* if fname="", we're checking if a base maildir has INBOX */
path = *fname == '\0' ? t_strdup_printf("%s/cur", dir) :
t_strdup_printf("%s/%s", dir, fname);
if (stat(path, &st) == 0) {
if (S_ISDIR(st.st_mode))
ret = 1;
else {
if (strncmp(fname, ".nfs", 4) == 0)
*flags |= MAILBOX_NONEXISTENT;
else
*flags |= MAILBOX_NOSELECT;
ret = 0;
}
} else if (errno == ENOENT) {
/* just deleted? */
*flags |= MAILBOX_NONEXISTENT;
ret = 0;
} else {
*flags |= MAILBOX_NOSELECT;
ret = 0;
}
} else {
ret = 1;
}
return ret;
}
uint32_t maildir_get_uidvalidity_next(struct mailbox_list *list)
{
const char *path;
path = mailbox_list_get_path(list, NULL,
MAILBOX_LIST_PATH_TYPE_CONTROL);
path = t_strconcat(path, "/"MAILDIR_UIDVALIDITY_FNAME, NULL);
return mailbox_uidvalidity_next(path);
}
static void maildir_storage_add_list(struct mail_storage *storage,
struct mailbox_list *list)
{
struct maildir_mailbox_list *mlist;
mlist = p_new(list->pool, struct maildir_mailbox_list, 1);
mlist->module_ctx.super = list->v;
mlist->set = mail_storage_get_driver_settings(storage);
if (strcmp(list->name, MAILBOX_LIST_NAME_MAILDIRPLUSPLUS) == 0) {
list->v.iter_is_mailbox = maildirplusplus_iter_is_mailbox;
} else {
list->v.is_valid_existing_name =
maildir_storage_is_valid_existing_name;
list->v.is_valid_create_name =
maildir_storage_is_valid_create_name;
list->v.iter_is_mailbox = maildir_list_iter_is_mailbox;
}
list->v.delete_mailbox = maildir_list_delete_mailbox;
list->v.rename_mailbox = maildir_list_rename_mailbox;
MODULE_CONTEXT_SET(list, maildir_mailbox_list_module, mlist);
}
struct mail_storage maildir_storage = {
MEMBER(name) MAILDIR_STORAGE_NAME,
MEMBER(class_flags) 0,
{
maildir_get_setting_parser_info,
maildir_storage_alloc,
maildir_storage_create,
index_storage_destroy,
maildir_storage_add_list,
maildir_storage_get_list_settings,
maildir_storage_autodetect,
maildir_mailbox_alloc,
NULL
}
};
struct mailbox maildir_mailbox = {
MEMBER(name) NULL,
MEMBER(storage) NULL,
MEMBER(list) NULL,
{
index_storage_is_readonly,
index_storage_allow_new_keywords,
index_storage_mailbox_enable,
maildir_mailbox_open,
maildir_mailbox_close,
maildir_mailbox_create,
maildir_mailbox_update,
maildir_storage_get_status,
maildir_list_index_has_changed,
maildir_list_index_update_sync,
maildir_storage_sync_init,
index_mailbox_sync_next,
index_mailbox_sync_deinit,
NULL,
maildir_notify_changes,
index_transaction_begin,
index_transaction_commit,
index_transaction_rollback,
index_transaction_set_max_modseq,
index_keywords_create,
index_keywords_create_from_indexes,
index_keywords_ref,
index_keywords_unref,
index_keyword_is_valid,
index_storage_get_seq_range,
index_storage_get_uid_range,
index_storage_get_expunges,
NULL,
NULL,
NULL,
index_mail_alloc,
index_header_lookup_init,
index_header_lookup_deinit,
index_storage_search_init,
index_storage_search_deinit,
index_storage_search_next_nonblock,
index_storage_search_next_update_seq,
maildir_save_alloc,
maildir_save_begin,
maildir_save_continue,
maildir_save_finish,
maildir_save_cancel,
maildir_copy,
index_storage_is_inconsistent
}
};