dbox-storage.c revision b811d88426068f2b959642e20348bfeeb9a6356d
5f5870385cff47efd2f58e7892f251cf13761528Timo Sirainen/* Copyright (C) 2005 Timo Sirainen */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include "subscription-file/subscription-file.h"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#define CREATE_MODE 0770 /* umask() should limit it more */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen/* Don't allow creating too long mailbox names. They could start causing
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen problems when they reach the limit. */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#define DBOX_MAX_MAILBOX_NAME_LENGTH (PATH_MAX/2)
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainenstatic bool dbox_handle_errors(struct index_storage *istorage)
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainen struct mail_storage *storage = &istorage->storage;
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen mail_storage_set_error(storage, MAIL_STORAGE_ERR_NO_PERMISSION);
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen mail_storage_set_error(storage, "Not enough disk space");
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen mail_storage_set_error(storage, "Directory structure is broken");
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainendbox_create(const char *data, const char *user,
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen bool debug = (flags & MAIL_STORAGE_FLAG_DEBUG) != 0;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* we won't do any guessing for this format. */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* <root dir> [:INDEX=<dir>] */
367e28a16854ee9f7247b2518f36f5e9163fcc10Timo Sirainen } while (p != NULL);
38f227941bcf673e0e523c1ac7267bca9cbcd2c4Timo Sirainen /* strip trailing '/' */
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen root_dir, index_dir == NULL ? "" : index_dir);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (mkdir_parents(root_dir, CREATE_MODE) < 0 && errno != EEXIST) {
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen i_error("mkdir_parents(%s) failed: %m", root_dir);
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen storage = p_new(pool, struct dbox_storage, 1);
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen istorage->index_dir = p_strdup(pool, home_expand(index_dir));
367e28a16854ee9f7247b2518f36f5e9163fcc10Timo Sirainen istorage->callbacks = p_new(pool, struct mail_storage_callbacks, 1);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen index_storage_init(istorage, flags, lock_method);
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainenstatic void dbox_free(struct mail_storage *_storage)
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen struct index_storage *storage = (struct index_storage *) _storage;
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainenstatic bool dbox_autodetect(const char *data, enum mail_storage_flags flags)
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen bool debug = (flags & MAIL_STORAGE_FLAG_DEBUG) != 0;
7af5f78e9fee296e42430d94ef252ff0333d8024Timo Sirainen path = t_strconcat(data, "/inbox/"DBOX_MAILDIR_NAME, NULL);
7af5f78e9fee296e42430d94ef252ff0333d8024Timo Sirainen i_info("dbox autodetect: stat(%s) failed: %m", path);
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen i_info("dbox autodetect: %s not a directory", path);
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainenbool dbox_is_valid_mask(struct mail_storage *storage, const char *mask)
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen const char *p;
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen if ((storage->flags & MAIL_STORAGE_FLAG_FULL_FS_ACCESS) != 0)
47569a4b2b4d3cc55e786177798c922c3c44233dTimo Sirainen /* make sure it's not absolute path */
1f5597beba229acd914e30a6da3c0e62d83b6e8fTimo Sirainen /* make sure the mailbox name doesn't contain any foolishness:
1f5597beba229acd914e30a6da3c0e62d83b6e8fTimo Sirainen "../" could give access outside the mailbox directory.
1f5597beba229acd914e30a6da3c0e62d83b6e8fTimo Sirainen "./" and "//" could fool ACL checks. */
47569a4b2b4d3cc55e786177798c922c3c44233dTimo Sirainen if (p[0] == '/')
47569a4b2b4d3cc55e786177798c922c3c44233dTimo Sirainen if (p[0] == '.') {
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen /* don't allow the dbox-Mails directory to be
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen used as part of the mask */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* "." and ".." aren't allowed. */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenstatic bool dbox_is_valid_create_name(struct mail_storage *storage,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if ((storage->flags & MAIL_STORAGE_FLAG_FULL_FS_ACCESS) == 0) {
002179a890bf4f1942cad6463787719eaa9fd6c0Timo Sirainenstatic bool dbox_is_valid_existing_name(struct mail_storage *storage,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenstatic const char *
f3e17726502b6cf1912f30aae7e283b5d31ea69cTimo Sirainendbox_get_path(struct index_storage *storage, const char *name)
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen if ((storage->storage.flags & MAIL_STORAGE_FLAG_FULL_FS_ACCESS) != 0 &&
002179a890bf4f1942cad6463787719eaa9fd6c0Timo Sirainen return t_strconcat(storage->dir, "/", name, NULL);
002179a890bf4f1942cad6463787719eaa9fd6c0Timo Sirainenstatic int create_dbox(struct index_storage *storage, const char *dir)
002179a890bf4f1942cad6463787719eaa9fd6c0Timo Sirainen path = t_strconcat(dir, "/", DBOX_MAILDIR_NAME, NULL);
002179a890bf4f1942cad6463787719eaa9fd6c0Timo Sirainen if (mkdir_parents(path, CREATE_MODE) < 0 && errno != EEXIST) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenstatic int create_index_dir(struct index_storage *storage, const char *name)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen const char *dir;
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen if (strcmp(storage->index_dir, storage->dir) == 0)
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainen dir = t_strconcat(storage->index_dir, "/", name,
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainen if (mkdir_parents(dir, CREATE_MODE) < 0 && errno != EEXIST) {
4c261fb48e6e36570a0841aa51ca483024d6a0a6Timo Sirainenstatic bool dbox_is_recent(struct index_mailbox *ibox __attr_unused__,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenstatic const char *
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainendbox_get_index_dir(struct index_storage *storage, const char *name)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen const char *p;
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen if ((storage->storage.flags & MAIL_STORAGE_FLAG_FULL_FS_ACCESS) != 0 &&
27ca6cb0548c6478005c77d04be641356ec7d83cTimo Sirainenstatic const char *
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainendbox_get_mailbox_path(struct mail_storage *_storage,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen struct dbox_storage *storage = (struct dbox_storage *)_storage;
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen struct index_storage *istorage = INDEX_STORAGE(storage);
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainenstatic const char *
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainendbox_get_mailbox_control_dir(struct mail_storage *_storage, const char *name)
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen struct dbox_storage *storage = (struct dbox_storage *)_storage;
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen struct index_storage *istorage = INDEX_STORAGE(storage);
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainenstatic const char *
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainendbox_get_mailbox_index_dir(struct mail_storage *_storage, const char *name)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen struct dbox_storage *storage = (struct dbox_storage *)_storage;
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainen struct index_storage *istorage = INDEX_STORAGE(storage);
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainenstatic struct mailbox *
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainendbox_open(struct dbox_storage *storage, const char *name,
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen struct index_storage *istorage = INDEX_STORAGE(storage);
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen index_dir = dbox_get_index_dir(istorage, name);
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen index = index_storage_alloc(index_dir, path, DBOX_INDEX_PREFIX);
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen pool = pool_alloconly_create("mailbox", 1024);
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen if (index_storage_mailbox_init(&mbox->ibox, index, name, flags,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* the memory was already freed */
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen mbox->rotate_size = (uoff_t)strtoul(value, NULL, 10) * 1024;
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen mbox->rotate_min_size = (uoff_t)strtoul(value, NULL, 10) * 1024;
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen mbox->rotate_min_size = DBOX_DEFAULT_ROTATE_MIN_SIZE;
b55f914c0ade77252cfd798ea8eb9a84bda56315Timo Sirainen mbox->rotate_days = (unsigned int)strtoul(value, NULL, 10);
19cadcc25c26af7afea1355d78e20ad64eaad263Timo Sirainenstatic struct mailbox *
19cadcc25c26af7afea1355d78e20ad64eaad263Timo Sirainendbox_mailbox_open(struct mail_storage *_storage, const char *name,
19cadcc25c26af7afea1355d78e20ad64eaad263Timo Sirainen struct istream *input, enum mailbox_open_flags flags)
19cadcc25c26af7afea1355d78e20ad64eaad263Timo Sirainen struct dbox_storage *storage = (struct dbox_storage *)_storage;
19cadcc25c26af7afea1355d78e20ad64eaad263Timo Sirainen struct index_storage *istorage = INDEX_STORAGE(storage);
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen "dbox doesn't support streamed mailboxes");
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen if (!dbox_is_valid_existing_name(_storage, name)) {
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen mail_storage_set_error(_storage, "Invalid mailbox name");
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen mail_storage_set_critical(_storage, "stat(%s) failed: %m",
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainenstatic int dbox_mailbox_create(struct mail_storage *_storage,
c06d6ea0766d0520af1a93e6000c0e73f350e0a2Timo Sirainen struct dbox_storage *storage = (struct dbox_storage *)_storage;
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen struct index_storage *istorage = INDEX_STORAGE(storage);
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen if (!dbox_is_valid_create_name(_storage, name)) {
c06d6ea0766d0520af1a93e6000c0e73f350e0a2Timo Sirainen mail_storage_set_error(_storage, "Invalid mailbox name");
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen mail_path = t_strconcat(path, "/", DBOX_MAILDIR_NAME, NULL);
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen mail_storage_set_error(_storage, "Mailbox already exists");
c06d6ea0766d0520af1a93e6000c0e73f350e0a2Timo Sirainenstatic int dbox_mailbox_delete(struct mail_storage *_storage,
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen struct dbox_storage *storage = (struct dbox_storage *)_storage;
c06d6ea0766d0520af1a93e6000c0e73f350e0a2Timo Sirainen struct index_storage *istorage = INDEX_STORAGE(storage);
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen mail_storage_set_error(_storage, "INBOX can't be deleted.");
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen if (!dbox_is_valid_existing_name(_storage, name)) {
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen mail_storage_set_error(_storage, "Invalid mailbox name");
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen mail_path = t_strconcat(path, "/", DBOX_MAILDIR_NAME, NULL);
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen if (stat(mail_path, &st) < 0 && ENOTFOUND(errno)) {
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen /* exists as a \NoSelect mailbox */
7f472e15b5f19a3536634863950c80a88079da23Timo Sirainen /* make sure the indexes are closed before trying to delete the
0139fcb57a88f6ed27a1bb4a1bd537b04fd2b5d6Timo Sirainen directory that contains them */
c06d6ea0766d0520af1a93e6000c0e73f350e0a2Timo Sirainen "unlink_directory() failed for %s: %m",
1503ac7619d97193d6690292b5f9523552c5d6ceTimo Sirainen /* try also removing the root directory. it can fail if the deleted
1503ac7619d97193d6690292b5f9523552c5d6ceTimo Sirainen mailbox had submailboxes. do it as long as we can. */
3c652e7a569c2623d22b4ab30279aebddce4d396Timo Sirainenstatic int dbox_mailbox_rename(struct mail_storage *_storage,
3c652e7a569c2623d22b4ab30279aebddce4d396Timo Sirainen struct index_storage *storage = (struct index_storage *)_storage;
3c652e7a569c2623d22b4ab30279aebddce4d396Timo Sirainen if (!dbox_is_valid_existing_name(_storage, oldname) ||
3c652e7a569c2623d22b4ab30279aebddce4d396Timo Sirainen !dbox_is_valid_create_name(_storage, newname)) {
3c652e7a569c2623d22b4ab30279aebddce4d396Timo Sirainen mail_storage_set_error(_storage, "Invalid mailbox name");
c06d6ea0766d0520af1a93e6000c0e73f350e0a2Timo Sirainen /* create the hierarchy */
47e9fdee55c2074425cf0316f4f64fbbb790301cTimo Sirainen "mkdir_parents(%s) failed: %m", p);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* first check that the destination mailbox doesn't exist.
62fc2fe221eccc834ac6b11b94b55335d5027cd1Timo Sirainen this is racy, but we need to be atomic and there's hardly any
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen possibility that someone actually tries to rename two mailboxes
62fc2fe221eccc834ac6b11b94b55335d5027cd1Timo Sirainen to same new one */
62fc2fe221eccc834ac6b11b94b55335d5027cd1Timo Sirainen "Target mailbox already exists");
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen "Target mailbox doesn't allow inferior mailboxes");
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen } else if (errno != ENOENT && errno != EACCES) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen mail_storage_set_critical(_storage, "lstat(%s) failed: %m",
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen /* NOTE: renaming INBOX works just fine with us, it's simply recreated
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen the next time it's needed. */
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen "rename(%s, %s) failed: %m", oldpath, newpath);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenstatic int dbox_set_subscribed(struct mail_storage *_storage,
c56500d4363beba4ffa954069ab30f4401849156Timo Sirainen struct dbox_storage *storage = (struct dbox_storage *)_storage;
c56500d4363beba4ffa954069ab30f4401849156Timo Sirainen path = t_strconcat(INDEX_STORAGE(storage)->dir,
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen return subsfile_set_subscribed(_storage, path,
47e9fdee55c2074425cf0316f4f64fbbb790301cTimo Sirainenstatic int dbox_get_mailbox_name_status(struct mail_storage *_storage,
47e9fdee55c2074425cf0316f4f64fbbb790301cTimo Sirainen struct index_storage *storage = (struct index_storage *)_storage;
0ee3fdb5e94ae6f34cb873ca3c9858342621e55fTimo Sirainen if (!dbox_is_valid_existing_name(_storage, name)) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen mail_path = t_strconcat(path, "/", DBOX_MAILDIR_NAME, NULL);
1b04762685272a53643ac2179939537a44c7c044Timo Sirainen if (strcmp(name, "INBOX") == 0 || stat(mail_path, &st) == 0) {
303e375b7e76278f4ec541f49af0476d3e4ee710Timo Sirainen if (!dbox_is_valid_create_name(_storage, name)) {
1388b590dbd85245b591346f860bc1319953318aTimo Sirainen mail_storage_set_critical(_storage, "stat(%s) failed: %m",
1388b590dbd85245b591346f860bc1319953318aTimo Sirainenstatic int dbox_storage_close(struct mailbox *box)
1388b590dbd85245b591346f860bc1319953318aTimo Sirainen struct dbox_mailbox *mbox = (struct dbox_mailbox *)box;
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainendbox_notify_changes(struct mailbox *box, unsigned int min_interval,
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen mailbox_notify_callback_t *callback, void *context)
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen struct dbox_mailbox *mbox = (struct dbox_mailbox *)box;
1388b590dbd85245b591346f860bc1319953318aTimo Sirainen mbox->ibox.min_notify_interval = min_interval;
1388b590dbd85245b591346f860bc1319953318aTimo Sirainen t_strconcat(mbox->path, "/"DBOX_MAILDIR_NAME, NULL));
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainenstatic void dbox_class_init(void)
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainenstatic void dbox_class_deinit(void)