#include "dbox-storage.h"
#include <stdio.h>
+#include <dirent.h>
+#include <unistd.h>
void dbox_storage_get_list_settings(const struct mail_namespace *ns ATTR_UNUSED,
struct mailbox_list_settings *set)
}
}
+static int dir_is_empty(struct mail_storage *storage, const char *path)
+{
+ DIR *dir;
+ struct dirent *d;
+ int ret = 1;
+
+ dir = opendir(path);
+ if (dir == NULL) {
+ if (errno == ENOENT) {
+ /* race condition with DELETE/RENAME? */
+ return 1;
+ }
+ mail_storage_set_critical(storage, "opendir(%s) failed: %m",
+ path);
+ return -1;
+ }
+ while ((d = readdir(dir)) != NULL) {
+ if (*d->d_name == '.')
+ continue;
+
+ ret = 0;
+ }
+ if (closedir(dir) < 0) {
+ mail_storage_set_critical(storage, "closedir(%s) failed: %m",
+ path);
+ ret = -1;
+ }
+ return ret;
+}
+
int dbox_mailbox_create(struct mailbox *box,
const struct mailbox_update *update, bool directory)
{
struct mail_index_sync_ctx *sync_ctx;
struct mail_index_view *view;
struct mail_index_transaction *trans;
+ const char *alt_path;
+ struct stat st;
int ret;
if (directory &&
if (index_storage_mailbox_open(box, FALSE) < 0)
return -1;
+ /* if alt path already exists and contains files, rebuild storage so
+ that we don't start overwriting files. */
+ alt_path = mailbox_list_get_path(box->list, box->name,
+ MAILBOX_LIST_PATH_TYPE_ALT_MAILBOX);
+ if (alt_path != NULL && stat(alt_path, &st) == 0) {
+ ret = dir_is_empty(box->storage, alt_path);
+ if (ret < 0)
+ return -1;
+ if (ret == 0) {
+ mail_storage_set_critical(&storage->storage,
+ "Mailbox %s has existing files in alt path, "
+ "rebuilding storage to avoid losing messages",
+ box->vname);
+ storage->v.set_mailbox_corrupted(box);
+ return -1;
+ }
+ /* dir is empty, ignore it */
+ }
+
/* use syncing as a lock */
ret = mail_index_sync_begin(box->index, &sync_ctx, &view, &trans, 0);
if (ret <= 0) {
int (*mailbox_create_indexes)(struct mailbox *box,
const struct mailbox_update *update,
struct mail_index_transaction *trans);
+ /* mark the mailbox corrupted */
+ void (*set_mailbox_corrupted)(struct mailbox *box);
/* mark the file corrupted */
void (*set_file_corrupted)(struct dbox_file *file);
};
}
}
+static void mdbox_set_mailbox_corrupted(struct mailbox *box)
+{
+ struct mdbox_storage *mstorage = (struct mdbox_storage *)box->storage;
+
+ mdbox_storage_set_corrupted(mstorage);
+}
+
static void mdbox_set_file_corrupted(struct dbox_file *file)
{
struct mdbox_storage *mstorage = (struct mdbox_storage *)file->storage;
mdbox_file_create_fd,
mdbox_mail_open,
mdbox_mailbox_create_indexes,
+ mdbox_set_mailbox_corrupted,
mdbox_set_file_corrupted
};
return ret;
}
-static void sdbox_set_file_corrupted(struct dbox_file *file ATTR_UNUSED)
+static void sdbox_set_mailbox_corrupted(struct mailbox *box ATTR_UNUSED)
{
/* FIXME */
}
+static void sdbox_set_file_corrupted(struct dbox_file *_file)
+{
+ struct sdbox_file *file = (struct sdbox_file *)_file;
+
+ sdbox_set_mailbox_corrupted(&file->mbox->box);
+}
+
static int
sdbox_mailbox_get_guid(struct mailbox *box, uint8_t guid[MAIL_GUID_128_SIZE])
{
sdbox_file_create_fd,
sdbox_mail_open,
sdbox_mailbox_create_indexes,
+ sdbox_set_mailbox_corrupted,
sdbox_set_file_corrupted
};
fs_list_create_mailbox_dir(struct mailbox_list *list, const char *name,
bool directory)
{
- const char *path, *alt_path, *gid_origin, *p;
- struct stat st;
+ const char *path, *gid_origin, *p;
mode_t mode;
gid_t gid;
bool create_parent_dir;
int ret;
- /* make sure the alt path doesn't exist yet. it shouldn't (except with
- race conditions with RENAME/DELETE), but if something crashed and
- left it lying around we don't want to start overwriting files in
- it. */
- if (!directory) {
- alt_path = mailbox_list_get_path(list, name,
- MAILBOX_LIST_PATH_TYPE_ALT_MAILBOX);
- if (alt_path != NULL && stat(alt_path, &st) == 0) {
- mailbox_list_set_error(list, MAIL_ERROR_EXISTS,
- "Mailbox already exists");
- return -1;
- }
- }
-
path = mailbox_list_get_path(list, name,
directory ? MAILBOX_LIST_PATH_TYPE_DIR :
MAILBOX_LIST_PATH_TYPE_MAILBOX);