maildir-storage.c revision 352cd70b5850eb0815f1ee3bb4e7533d2c8c4c5f
150b76e13b7c4f3ccf1d709bf517ca2af6b2c9a2Jakub Hrozek/* Copyright (c) 2002-2011 Dovecot authors, see the included COPYING file */
150b76e13b7c4f3ccf1d709bf517ca2af6b2c9a2Jakub Hrozek MODULE_CONTEXT(obj, maildir_mailbox_list_module)
150b76e13b7c4f3ccf1d709bf517ca2af6b2c9a2Jakub Hrozekstatic MODULE_CONTEXT_DEFINE_INIT(maildir_mailbox_list_module,
8d5292227a8d1ab9c6aa5b88d8ac8655cd1223e5Pavel Březinastatic const char *maildir_subdirs[] = { "cur", "new", "tmp" };
36c266d467e9105041b33e9b1cdcd9ff073d893eSumit Bosestatic struct mail_storage *maildir_storage_alloc(void)
150b76e13b7c4f3ccf1d709bf517ca2af6b2c9a2Jakub Hrozek pool = pool_alloconly_create("maildir storage", 512+256);
50c9d542e8bf641412debaa82a4dcf67ddb72258Lukas Slebodnik storage = p_new(pool, struct maildir_storage, 1);
150b76e13b7c4f3ccf1d709bf517ca2af6b2c9a2Jakub Hrozekmaildir_storage_create(struct mail_storage *_storage, struct mail_namespace *ns,
150b76e13b7c4f3ccf1d709bf517ca2af6b2c9a2Jakub Hrozek struct maildir_storage *storage = (struct maildir_storage *)_storage;
150b76e13b7c4f3ccf1d709bf517ca2af6b2c9a2Jakub Hrozek const char *dir;
150b76e13b7c4f3ccf1d709bf517ca2af6b2c9a2Jakub Hrozek storage->set = mail_storage_get_driver_settings(_storage);
150b76e13b7c4f3ccf1d709bf517ca2af6b2c9a2Jakub Hrozek storage->temp_prefix = p_strdup(_storage->pool,
e4549c5364461644723361d688badde7fe137a25Sumit Bose if (list->set.control_dir == NULL && list->set.inbox_path == NULL &&
150b76e13b7c4f3ccf1d709bf517ca2af6b2c9a2Jakub Hrozek /* put the temp files into tmp/ directory preferrably */
150b76e13b7c4f3ccf1d709bf517ca2af6b2c9a2Jakub Hrozek storage->temp_prefix = p_strconcat(_storage->pool, "tmp/",
36c266d467e9105041b33e9b1cdcd9ff073d893eSumit Bose /* control dir should also be writable */
150b76e13b7c4f3ccf1d709bf517ca2af6b2c9a2Jakub Hrozek _storage->temp_path_prefix = p_strconcat(_storage->pool, dir, "/",
36c266d467e9105041b33e9b1cdcd9ff073d893eSumit Bosestatic void maildir_storage_get_list_settings(const struct mail_namespace *ns,
36c266d467e9105041b33e9b1cdcd9ff073d893eSumit Bose set->subscription_fname = MAILDIR_SUBSCRIPTION_FILE_NAME;
150b76e13b7c4f3ccf1d709bf517ca2af6b2c9a2Jakub Hrozek if (set->inbox_path == NULL && set->maildir_name == NULL &&
150b76e13b7c4f3ccf1d709bf517ca2af6b2c9a2Jakub Hrozek (strcmp(set->layout, MAILBOX_LIST_NAME_MAILDIRPLUSPLUS) == 0 ||
150b76e13b7c4f3ccf1d709bf517ca2af6b2c9a2Jakub Hrozek strcmp(set->layout, MAILBOX_LIST_NAME_FS) == 0) &&
150b76e13b7c4f3ccf1d709bf517ca2af6b2c9a2Jakub Hrozek /* Maildir++ INBOX is the Maildir base itself */
150b76e13b7c4f3ccf1d709bf517ca2af6b2c9a2Jakub Hrozekstatic const char *
150b76e13b7c4f3ccf1d709bf517ca2af6b2c9a2Jakub Hrozekmaildir_storage_find_root_dir(const struct mail_namespace *ns)
150b76e13b7c4f3ccf1d709bf517ca2af6b2c9a2Jakub Hrozek /* we'll need to figure out the maildir location ourself.
150b76e13b7c4f3ccf1d709bf517ca2af6b2c9a2Jakub Hrozek It's ~/Maildir unless we are chrooted. */
150b76e13b7c4f3ccf1d709bf517ca2af6b2c9a2Jakub Hrozek i_debug("maildir: access(%s, rwx): failed: %m", path);
150b76e13b7c4f3ccf1d709bf517ca2af6b2c9a2Jakub Hrozek i_debug("maildir: /cur exists, assuming chroot");
4f3a9d837a55b49448eca3c713c85a406207e523Simo Sorcestatic bool maildir_storage_autodetect(const struct mail_namespace *ns,
343b053bc61792023003d077ae81c05ff1676a89Sumit Bose i_debug("maildir autodetect: stat(%s) failed: %m", path);
150b76e13b7c4f3ccf1d709bf517ca2af6b2c9a2Jakub Hrozek i_debug("maildir autodetect: %s not a directory", path);
35567de112cd5d82acb582cbdb44c8652bbdfda1Lukas Slebodnikmkdir_verify(struct mail_storage *storage, struct mail_namespace *ns,
150b76e13b7c4f3ccf1d709bf517ca2af6b2c9a2Jakub Hrozek const char *dir, mode_t mode, gid_t gid, const char *gid_origin,
54039570d26e29444c398aa4ad6ba638f1713566Sumit Bose if (mkdir_parents_chgrp(dir, mode, gid, gid_origin) == 0)
54039570d26e29444c398aa4ad6ba638f1713566Sumit Bose mail_storage_set_error(storage, MAIL_ERROR_EXISTS,
54039570d26e29444c398aa4ad6ba638f1713566Sumit Bose "Mailbox already exists");
54039570d26e29444c398aa4ad6ba638f1713566Sumit Bose mail_storage_set_error(storage, MAIL_ERROR_NOTFOUND,
54039570d26e29444c398aa4ad6ba638f1713566Sumit Bose "Mailbox was deleted while it was being created");
35567de112cd5d82acb582cbdb44c8652bbdfda1Lukas Slebodnik /* shared namespace, don't log permission errors */
a044c9a1012d11a2a75e9976ebf186d2d781d291Pallavi Jhastatic int maildir_check_tmp(struct mail_storage *storage, const char *dir)
bbd6f73bbad478a450ecfa2933a63de6dc269778Jakub Hrozek const char *path;
bbd6f73bbad478a450ecfa2933a63de6dc269778Jakub Hrozek /* if tmp/ directory exists, we need to clean it up once in a while */
1a45124f3f300f9afdcb08eab0938e5e7d0534d9Sumit Bose mail_storage_set_critical(storage, "stat(%s) failed: %m", path);
1a45124f3f300f9afdcb08eab0938e5e7d0534d9Sumit Bose if (st.st_atime > st.st_ctime + MAILDIR_TMP_DELETE_SECS) {
35567de112cd5d82acb582cbdb44c8652bbdfda1Lukas Slebodnik /* the directory should be empty. we won't do anything
1a45124f3f300f9afdcb08eab0938e5e7d0534d9Sumit Bose until ctime changes. */
1a45124f3f300f9afdcb08eab0938e5e7d0534d9Sumit Bose } else if (st.st_atime < ioloop_time - MAILDIR_TMP_SCAN_SECS) {
1a45124f3f300f9afdcb08eab0938e5e7d0534d9Sumit Bose /* time to scan */
8d5292227a8d1ab9c6aa5b88d8ac8655cd1223e5Pavel Březina/* create or fix maildir, ignore if it already exists */
8d5292227a8d1ab9c6aa5b88d8ac8655cd1223e5Pavel Březinastatic int create_maildir(struct mailbox *box, bool verify)
8d5292227a8d1ab9c6aa5b88d8ac8655cd1223e5Pavel Březina const struct mailbox_permissions *perm = mailbox_get_permissions(box);
8d5292227a8d1ab9c6aa5b88d8ac8655cd1223e5Pavel Březina unsigned int i;
8d5292227a8d1ab9c6aa5b88d8ac8655cd1223e5Pavel Březina for (i = 0; i < N_ELEMENTS(maildir_subdirs); i++) {
8d5292227a8d1ab9c6aa5b88d8ac8655cd1223e5Pavel Březina path = t_strconcat(mailbox_get_path(box), "/",
8d5292227a8d1ab9c6aa5b88d8ac8655cd1223e5Pavel Březina if (mkdir_verify(box->storage, box->list->ns, path,
8d5292227a8d1ab9c6aa5b88d8ac8655cd1223e5Pavel Březina /* try to create all of the directories in case one
8d5292227a8d1ab9c6aa5b88d8ac8655cd1223e5Pavel Březina of them doesn't exist */
8d5292227a8d1ab9c6aa5b88d8ac8655cd1223e5Pavel Březinastatic void maildir_lock_touch_timeout(struct maildir_mailbox *mbox)
8d5292227a8d1ab9c6aa5b88d8ac8655cd1223e5Pavel Březina (void)maildir_uidlist_lock_touch(mbox->uidlist);
8d5292227a8d1ab9c6aa5b88d8ac8655cd1223e5Pavel Březinastatic struct mailbox *
8d5292227a8d1ab9c6aa5b88d8ac8655cd1223e5Pavel Březinamaildir_mailbox_alloc(struct mail_storage *storage, struct mailbox_list *list,
8d5292227a8d1ab9c6aa5b88d8ac8655cd1223e5Pavel Březina pool = pool_alloconly_create("maildir mailbox", 1024*3);
8d5292227a8d1ab9c6aa5b88d8ac8655cd1223e5Pavel Březina mbox = p_new(pool, struct maildir_mailbox, 1);
a044c9a1012d11a2a75e9976ebf186d2d781d291Pallavi Jha index_storage_mailbox_alloc(&mbox->box, vname, flags,
a044c9a1012d11a2a75e9976ebf186d2d781d291Pallavi Jha mbox->storage = (struct maildir_storage *)storage;
a044c9a1012d11a2a75e9976ebf186d2d781d291Pallavi Jhastatic int maildir_mailbox_open_existing(struct mailbox *box)
a044c9a1012d11a2a75e9976ebf186d2d781d291Pallavi Jha struct maildir_mailbox *mbox = (struct maildir_mailbox *)box;
150b76e13b7c4f3ccf1d709bf517ca2af6b2c9a2Jakub Hrozek if ((box->flags & MAILBOX_FLAG_KEEP_LOCKED) != 0) {
150b76e13b7c4f3ccf1d709bf517ca2af6b2c9a2Jakub Hrozek mbox->keep_lock_to = timeout_add(MAILDIR_LOCK_TOUCH_SECS * 1000,
bbd6f73bbad478a450ecfa2933a63de6dc269778Jakub Hrozek if (index_storage_mailbox_open(box, FALSE) < 0)
bbd6f73bbad478a450ecfa2933a63de6dc269778Jakub Hrozek mail_index_ext_register(mbox->box.index, "maildir",
150b76e13b7c4f3ccf1d709bf517ca2af6b2c9a2Jakub Hrozekstatic bool maildir_storage_is_readonly(struct mailbox *box)
150b76e13b7c4f3ccf1d709bf517ca2af6b2c9a2Jakub Hrozek struct maildir_mailbox *mbox = (struct maildir_mailbox *)box;
150b76e13b7c4f3ccf1d709bf517ca2af6b2c9a2Jakub Hrozek /* return read-only only if there are no private flags
34926c3809b19f9e70f18931e44bf993321647a8Jakub Hrozek (that are stored in index files) */
150b76e13b7c4f3ccf1d709bf517ca2af6b2c9a2Jakub Hrozekmaildir_mailbox_exists(struct mailbox *box, bool auto_boxes ATTR_UNUSED,
150b76e13b7c4f3ccf1d709bf517ca2af6b2c9a2Jakub Hrozek return index_storage_mailbox_exists_full(box, "cur", existence_r);
34926c3809b19f9e70f18931e44bf993321647a8Jakub Hrozekstatic int maildir_mailbox_open(struct mailbox *box)
34926c3809b19f9e70f18931e44bf993321647a8Jakub Hrozek /* begin by checking if tmp/ directory exists and if it should be
34926c3809b19f9e70f18931e44bf993321647a8Jakub Hrozek cleaned up. */
34926c3809b19f9e70f18931e44bf993321647a8Jakub Hrozek ret = maildir_check_tmp(box->storage, box_path);
34926c3809b19f9e70f18931e44bf993321647a8Jakub Hrozek /* exists */
34926c3809b19f9e70f18931e44bf993321647a8Jakub Hrozek /* tmp/ directory doesn't exist. does the maildir? */
34926c3809b19f9e70f18931e44bf993321647a8Jakub Hrozek root_dir = mailbox_list_get_path(box->list, NULL,
34926c3809b19f9e70f18931e44bf993321647a8Jakub Hrozek /* root directory. either INBOX or some other namespace root */
34926c3809b19f9e70f18931e44bf993321647a8Jakub Hrozek /* yes, we'll need to create the missing dirs */
34926c3809b19f9e70f18931e44bf993321647a8Jakub Hrozek mail_storage_set_error(box->storage, MAIL_ERROR_NOTFOUND,
aa648535f445e7a95bf6dedc7c43bb5f94ab7354Jakub Hrozekstatic int maildir_create_shared(struct mailbox *box)
aa648535f445e7a95bf6dedc7c43bb5f94ab7354Jakub Hrozek const struct mailbox_permissions *perm = mailbox_get_permissions(box);
aa648535f445e7a95bf6dedc7c43bb5f94ab7354Jakub Hrozek const char *path;
aa648535f445e7a95bf6dedc7c43bb5f94ab7354Jakub Hrozek path = t_strconcat(mailbox_get_path(box), "/dovecot-shared", NULL);
aa648535f445e7a95bf6dedc7c43bb5f94ab7354Jakub Hrozek fd = open(path, O_WRONLY | O_CREAT, perm->file_create_mode);
aa648535f445e7a95bf6dedc7c43bb5f94ab7354Jakub Hrozek mail_storage_set_critical(box->storage, "open(%s) failed: %m",
2dcf7b9b65df21f2aee6cdf051a7fbdef6dfe034Jakub Hrozek if (fchown(fd, (uid_t)-1, perm->file_create_gid) < 0) {
2dcf7b9b65df21f2aee6cdf051a7fbdef6dfe034Jakub Hrozekmaildir_mailbox_update(struct mailbox *box, const struct mailbox_update *update)
2dcf7b9b65df21f2aee6cdf051a7fbdef6dfe034Jakub Hrozek struct maildir_mailbox *mbox = (struct maildir_mailbox *)box;
a3442e4a268ad2172c89d58e6daa759eb4b39e7cFabiano Fidêncio if (!guid_128_is_empty(update->mailbox_guid))
a3442e4a268ad2172c89d58e6daa759eb4b39e7cFabiano Fidêncio maildir_uidlist_set_mailbox_guid(uidlist, update->mailbox_guid);
a3442e4a268ad2172c89d58e6daa759eb4b39e7cFabiano Fidêncio maildir_uidlist_set_uid_validity(uidlist, update->uid_validity);
a3442e4a268ad2172c89d58e6daa759eb4b39e7cFabiano Fidêncio maildir_uidlist_set_next_uid(uidlist, update->min_next_uid,
a3442e4a268ad2172c89d58e6daa759eb4b39e7cFabiano Fidêncio ret = index_storage_mailbox_update(box, update);
a3442e4a268ad2172c89d58e6daa759eb4b39e7cFabiano Fidênciomaildir_mailbox_create(struct mailbox *box, const struct mailbox_update *update,
2dcf7b9b65df21f2aee6cdf051a7fbdef6dfe034Jakub Hrozek (box->list->props & MAILBOX_LIST_PROP_NO_NOSELECT) == 0)
2dcf7b9b65df21f2aee6cdf051a7fbdef6dfe034Jakub Hrozek ret = maildir_check_tmp(box->storage, mailbox_get_path(box));
2dcf7b9b65df21f2aee6cdf051a7fbdef6dfe034Jakub Hrozek mail_storage_set_error(box->storage, MAIL_ERROR_EXISTS,
2dcf7b9b65df21f2aee6cdf051a7fbdef6dfe034Jakub Hrozek "Mailbox already exists");
2dcf7b9b65df21f2aee6cdf051a7fbdef6dfe034Jakub Hrozek /* if dovecot-shared exists in the root dir, copy it to newly
2dcf7b9b65df21f2aee6cdf051a7fbdef6dfe034Jakub Hrozek created mailboxes */
2dcf7b9b65df21f2aee6cdf051a7fbdef6dfe034Jakub Hrozek root_dir = mailbox_list_get_path(box->list, NULL,
2dcf7b9b65df21f2aee6cdf051a7fbdef6dfe034Jakub Hrozek shared_path = t_strconcat(root_dir, "/dovecot-shared", NULL);
2dcf7b9b65df21f2aee6cdf051a7fbdef6dfe034Jakub Hrozek return update == NULL ? 0 : maildir_mailbox_update(box, update);
2dcf7b9b65df21f2aee6cdf051a7fbdef6dfe034Jakub Hrozekmaildir_mailbox_get_metadata(struct mailbox *box,
2dcf7b9b65df21f2aee6cdf051a7fbdef6dfe034Jakub Hrozek struct maildir_mailbox *mbox = (struct maildir_mailbox *)box;
2dcf7b9b65df21f2aee6cdf051a7fbdef6dfe034Jakub Hrozek if (maildir_uidlist_get_mailbox_guid(mbox->uidlist,
2dcf7b9b65df21f2aee6cdf051a7fbdef6dfe034Jakub Hrozek return index_mailbox_get_metadata(box, items, metadata_r);
2dcf7b9b65df21f2aee6cdf051a7fbdef6dfe034Jakub Hrozekstatic void maildir_mailbox_close(struct mailbox *box)
2dcf7b9b65df21f2aee6cdf051a7fbdef6dfe034Jakub Hrozek struct maildir_mailbox *mbox = (struct maildir_mailbox *)box;
2dcf7b9b65df21f2aee6cdf051a7fbdef6dfe034Jakub Hrozekstatic void maildir_notify_changes(struct mailbox *box)
2dcf7b9b65df21f2aee6cdf051a7fbdef6dfe034Jakub Hrozek struct maildir_mailbox *mbox = (struct maildir_mailbox *)box;
a3442e4a268ad2172c89d58e6daa759eb4b39e7cFabiano Fidêncio index_mailbox_check_remove_all(&mbox->box);
a3442e4a268ad2172c89d58e6daa759eb4b39e7cFabiano Fidênciomaildir_is_internal_name(struct mailbox_list *list ATTR_UNUSED,
a3442e4a268ad2172c89d58e6daa759eb4b39e7cFabiano Fidênciostatic void maildir_storage_add_list(struct mail_storage *storage,
2dcf7b9b65df21f2aee6cdf051a7fbdef6dfe034Jakub Hrozek mlist = p_new(list->pool, struct maildir_mailbox_list_context, 1);
2dcf7b9b65df21f2aee6cdf051a7fbdef6dfe034Jakub Hrozek mlist->set = mail_storage_get_driver_settings(storage);
2dcf7b9b65df21f2aee6cdf051a7fbdef6dfe034Jakub Hrozek list->v.is_internal_name = maildir_is_internal_name;
2dcf7b9b65df21f2aee6cdf051a7fbdef6dfe034Jakub Hrozek MODULE_CONTEXT_SET(list, maildir_mailbox_list_module, mlist);
2dcf7b9b65df21f2aee6cdf051a7fbdef6dfe034Jakub Hrozekuint32_t maildir_get_uidvalidity_next(struct mailbox_list *list)
2dcf7b9b65df21f2aee6cdf051a7fbdef6dfe034Jakub Hrozek const char *path;
2dcf7b9b65df21f2aee6cdf051a7fbdef6dfe034Jakub Hrozek path = t_strconcat(path, "/"MAILDIR_UIDVALIDITY_FNAME, NULL);
2dcf7b9b65df21f2aee6cdf051a7fbdef6dfe034Jakub Hrozekstatic enum mail_flags maildir_get_private_flags_mask(struct mailbox *box)
2dcf7b9b65df21f2aee6cdf051a7fbdef6dfe034Jakub Hrozek struct maildir_mailbox *mbox = (struct maildir_mailbox *)box;
2dcf7b9b65df21f2aee6cdf051a7fbdef6dfe034Jakub Hrozek /* no separate index directory. we can't have private flags,
2dcf7b9b65df21f2aee6cdf051a7fbdef6dfe034Jakub Hrozek so don't even bother checking if dovecot-shared exists */
2dcf7b9b65df21f2aee6cdf051a7fbdef6dfe034Jakub Hrozekbool maildir_is_backend_readonly(struct maildir_mailbox *mbox)
a3442e4a268ad2172c89d58e6daa759eb4b39e7cFabiano Fidêncio const char *box_path = mailbox_get_path(&mbox->box);
a3442e4a268ad2172c89d58e6daa759eb4b39e7cFabiano Fidêncio if (access(t_strconcat(box_path, "/cur", NULL), W_OK) < 0 &&