dbox-storage.c revision 0c3cde7382518b486092bfae64bb6a948405854a
/* Copyright (c) 2007-2009 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "array.h"
#include "ioloop.h"
#include "str.h"
#include "hex-binary.h"
#include "randgen.h"
#include "mkdir-parents.h"
#include "unlink-directory.h"
#include "unlink-old-files.h"
#include "index-mail.h"
#include "mail-copy.h"
#include "mailbox-uidvalidity.h"
#include "maildir/maildir-uidlist.h"
#include "dbox-map.h"
#include "dbox-file.h"
#include "dbox-sync.h"
#include "dbox-storage-rebuild.h"
#include "dbox-storage.h"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <dirent.h>
#define DBOX_LIST_CONTEXT(obj) \
struct dbox_mailbox_list {
const struct dbox_settings *set;
};
extern struct mail_storage dbox_storage;
extern struct mailbox dbox_mailbox;
static struct mail_storage *dbox_storage_alloc(void)
{
struct dbox_storage *storage;
}
static int
const char **error_r)
{
*error_r = "dbox: MAILBOXDIR must not be empty";
return -1;
}
return 0;
}
{
if (storage->sync_rebuild) {
if (dbox_storage_rebuild(storage) < 0)
return;
}
}
static void
struct mailbox_list_settings *set)
{
}
static const char *
{
#if 0 // FIXME
const char *root;
unsigned int len;
return NULL;
/* can't determine the alt path - shouldn't happen */
return NULL;
}
#endif
return NULL;
}
struct mailbox *
enum mailbox_flags flags)
{
struct dbox_mailbox *mbox;
/* dbox can't work without index files */
mbox->dbox_ext_id =
sizeof(struct dbox_mail_index_record),
sizeof(uint32_t));
sizeof(struct dbox_index_header), 0, 0);
mbox->guid_ext_id =
0, MAIL_GUID_128_SIZE, 1);
}
{
const char *path;
return mailbox_uidvalidity_next(path);
}
{
const void *data;
if (data_size < DBOX_INDEX_HEADER_MIN_SIZE &&
"dbox %s: Invalid dbox header size",
return -1;
}
return 0;
}
struct mail_index_transaction *trans,
const struct mailbox_update *update)
{
sizeof(new_hdr.mailbox_guid));
}
}
}
const struct mailbox_update *update)
{
struct mail_index_transaction *trans;
const struct mail_index_header *hdr;
return -1;
else if (hdr->uid_validity == 0) {
/* set uidvalidity */
}
}
}
if (mail_index_transaction_commit(&trans) < 0) {
return -1;
}
return 0;
}
const struct mailbox_update *update)
{
const char *origin;
int ret;
/* create indexes immediately with the dbox header */
if (index_storage_mailbox_open(box) < 0)
return -1;
if (ret < 0)
return -1;
}
return -1;
}
return 0;
}
static bool
{
return FALSE;
/* check once in a while if there are temp files to clean up */
/* there haven't been any changes to this directory since we
last checked it. */
/* time to scan */
const char *prefix =
}
return TRUE;
}
{
"dbox doesn't support streamed mailboxes");
return -1;
}
return index_storage_mailbox_open(box);
/* INBOX always exists, create it */
return -1;
}
return -1;
return -1;
} else {
return -1;
}
}
{
}
struct mailbox_status *status_r)
{
struct dbox_index_header hdr;
/* regenerate it */
return;
}
sizeof(status_r->mailbox_guid));
}
static void
struct mailbox_status *status_r)
{
if ((items & STATUS_GUID) != 0)
}
static int
bool directory)
{
"Mailbox already exists");
return -1;
}
if (directory) {
return 0;
"Mailbox already exists");
"mkdir(%s) failed: %m", path);
}
return -1;
}
/* make sure the alt path doesn't exist yet. it shouldn't (except with
left it lying around we don't want to start overwriting files in
it. */
"Mailbox already exists");
return -1;
}
}
static int
{
if (index_storage_mailbox_open(box) < 0)
return -1;
}
}
static int
{
const struct mail_storage_settings *old_set;
struct mail_storage_settings tmp_set;
struct dbox_mailbox *mbox;
const struct mail_index_header *hdr;
const struct dbox_mail_index_record *dbox_rec;
struct dbox_map_transaction_context *map_trans;
const void *data;
bool expunged;
int ret;
if (ret < 0) {
mailbox_close(&box);
return -1;
}
/* get a list of all map_uids in this mailbox */
/* no multi-mails */
break;
}
}
/* unreference the map_uids */
if (ret == 0)
mailbox_close(&box);
return ret;
}
static const char *dbox_get_trash_dest(const char *trash_dir)
{
const char *path;
unsigned char randbuf[16];
do {
return path;
}
static int
{
int ret;
/* 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. */
/* delete the index and control directories */
return -1;
/* first try renaming the actual mailbox to trash directory */
/* either source mailbox doesn't exist or trash directory
doesn't exist. try creating the trash and retrying. */
const char *origin;
"mkdir(%s) failed: %m", trash_dir);
return -1;
}
}
if (ret == 0) {
/* we've already renamed it. there's no going back. */
ret = -1;
}
"unlink_directory(%s) failed: %m", trash_dest);
ret = -1;
}
/* if there's an alt path, delete it too */
"unlink_directory(%s) failed: %m", alt_path);
ret = -1;
}
}
/* try to delete the parent directory also */
return -1;
} else {
/* mailbox not found - what about the directory? */
/* delete the directory */
return -1;
} else if (!mailbox_list_set_error_from_errno(list)) {
path);
return -1;
}
ret = 0;
}
return ret;
if (deleted)
return ret;
t_strdup_printf("Directory %s isn't empty, "
"can't delete it.", name));
} else if (!mailbox_list_set_error_from_errno(list)) {
path);
}
return -1;
}
static int
const char *oldname,
struct mailbox_list *newlist,
const char *newname,
{
const char *path;
return 0;
/* destination dbox storage doesn't have alt-path defined.
we can't do the rename easily. */
"Can't rename mailboxes across specified storages.");
return -1;
}
return 1;
}
static int
const char *oldname,
struct mailbox_list *newlist,
const char *newname)
{
const char *alt_oldpath, *alt_newpath;
int ret;
&alt_oldpath, &alt_newpath);
if (ret <= 0)
return ret;
/* race condition or a directory left there lying around?
safest to just report error. */
"Target mailbox already exists");
return -1;
return -1;
}
return 0;
}
static int
bool rename_children)
{
int ret;
if (ret < 0)
return -1;
&alt_newpath);
if (ret <= 0)
return ret;
/* ok */
if (!rename_children) {
"rmdir(%s) failed: %m", path);
}
}
/* renaming is done already, so just log the error */
}
return 0;
}
{
const char *path;
else {
}
}
const char *mailbox_name ATTR_UNUSED,
enum mailbox_list_file_type type,
enum mailbox_info_flags *flags)
{
const char *path, *maildir_path;
int ret = 1;
/* try to avoid stat() with these checks */
if (type != MAILBOX_LIST_FILE_TYPE_DIR &&
/* it's a file */
return 0;
}
/* need to stat() then */
/* non-directory */
ret = 0;
/* no subdirectories */
*flags |= MAILBOX_NOCHILDREN;
/* default configuration: we have one directory
containing the mailboxes. if there are 3 links,
either this is a selectable mailbox without children
or non-selectable mailbox with children */
*flags |= MAILBOX_CHILDREN;
} else {
/* non-default configuration: all subdirectories are
child mailboxes. */
*flags |= MAILBOX_CHILDREN;
}
/* doesn't exist - probably a non-existing subscribed mailbox */
*flags |= MAILBOX_NONEXISTENT;
} else {
/* non-selectable. probably either access denied, or symlink
destination not found. don't bother logging errors. */
*flags |= MAILBOX_NOSELECT;
}
/* make sure it's a selectable mailbox */
*flags |= MAILBOX_NOSELECT;
/* now we know what link count 3 means. */
if ((*flags & MAILBOX_NOSELECT) != 0)
*flags |= MAILBOX_CHILDREN;
else
*flags |= MAILBOX_NOCHILDREN;
}
}
return ret;
}
struct mailbox_list *list)
{
struct dbox_mailbox_list *mlist;
}
struct mail_storage dbox_storage = {
{
NULL,
}
};
struct mailbox dbox_mailbox = {
{
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
}
};