maildir-storage.c revision 27c77e7115d2b3145fcde9d99b93049b8209d19e
/* Copyright (C) 2002-2006 Timo Sirainen */
#include "lib.h"
#include "array.h"
#include "hostpid.h"
#include "home-expand.h"
#include "mkdir-parents.h"
#include "unlink-directory.h"
#include "subscription-file/subscription-file.h"
#include "maildir-storage.h"
#include "maildir-uidlist.h"
#include "maildir-keywords.h"
#include "index-mail.h"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
/* Don't allow creating too long mailbox names. They could start causing
problems when they reach the limit. */
struct rename_context {
bool found;
const char *newname;
};
extern struct mail_storage maildir_storage;
extern struct mailbox maildir_mailbox;
static struct mail_storage *
enum mail_storage_flags flags,
{
struct maildir_storage *storage;
struct index_storage *istorage;
/* we'll need to figure out the maildir location ourself.
if (debug) {
i_info("maildir: root exists (%s)",
path);
}
} else {
if (debug) {
i_info("maildir: access(%s, rwx): "
"failed: %m", path);
}
}
} else {
if (debug)
i_info("maildir: HOME not set");
}
if (debug)
i_info("maildir: /cur exists, assuming chroot");
root_dir = "/";
}
} else {
/* <Maildir> [:INBOX=<dir>] [:INDEX=<dir>] [:CONTROL=<dir>] */
if (debug)
if (p == NULL)
else {
do {
p++;
p = strchr(p, ':');
} while (p != NULL);
}
}
if (debug)
i_info("maildir: couldn't find root dir");
return NULL;
}
/* strip trailing '/' */
if (debug) {
i_info("maildir: root=%s, index=%s, control=%s, inbox=%s",
}
/* the default ".temp.xxx" prefix would be treated as directory */
(void)verify_inbox(storage);
}
{
}
{
const char *path;
if (debug)
return FALSE;
}
if (debug)
return FALSE;
}
return TRUE;
}
const char *name)
{
/* check that there are no adjacent hierarchy separators */
return FALSE;
}
return FALSE;
return TRUE;
return FALSE;
/* "." and ".." aren't allowed. */
return FALSE;
}
return FALSE;
return TRUE;
}
const char *name)
{
return FALSE;
return TRUE;
return FALSE;
/* "." and ".." aren't allowed. */
return FALSE;
}
return TRUE;
}
static const char *maildir_get_absolute_path(const char *name)
{
const char *p;
if (p == NULL)
return name;
}
{
return maildir_get_absolute_path(name);
}
}
static const char *
{
return NULL;
}
const char *name)
{
return NULL;
return maildir_get_absolute_path(name);
}
const char *name)
{
return maildir_get_absolute_path(name);
}
{
if (verify) {
return 0;
"lstat(%s) failed: %m", dir);
return -1;
}
}
"mkdir(%s) failed: %m", dir);
}
return -1;
}
return 0;
}
/* create or fix maildir, ignore if it already exists */
{
return -1;
return -1;
/* small optimization. if we're verifying, we don't
check that the root dir actually exists unless we
fail here. */
return -1;
return -1;
}
}
return 0;
}
{
const char *dir;
return 0;
return 0;
"mkdir(%s) failed: %m", dir);
return -1;
}
return 0;
}
{
const char *dir;
return 0;
"mkdir(%s) failed: %m", dir);
return -1;
}
return 0;
}
{
const char *path;
return -1;
/* make sure the index directories exist */
return -1;
return -1;
return 0;
}
{
}
static struct mailbox *
enum mailbox_open_flags flags)
{
struct maildir_mailbox *mbox;
struct mail_index *index;
int shared;
if ((flags & MAILBOX_OPEN_NO_INDEX_FILES) != 0)
/* for shared mailboxes get the create mode from the
permissions of dovecot-shared file. */
if (shared)
FALSE) < 0) {
/* the memory was already freed */
return NULL;
}
if (!shared)
else {
}
mailbox_close(&box);
return NULL;
}
}
}
static const char *
{
if (*name == '\0')
}
static const char *
{
}
static struct mailbox *
{
const char *path;
"Maildir doesn't support streamed mailboxes");
return NULL;
}
if (verify_inbox(storage) < 0)
return NULL;
}
return NULL;
}
/* exists - make sure the required directories are also there */
return NULL;
if ((flags & MAILBOX_OPEN_NO_INDEX_FILES) == 0) {
return NULL;
}
return NULL;
} else {
path);
return NULL;
}
}
{
int fd;
if (fd == -1) {
"open(%s) failed: %m", path);
return -1;
}
"fchown(%s) failed: %m", path);
}
return 0;
}
const char *name,
bool directory __attr_unused__)
{
const char *path, *shared_path;
return -1;
}
"Mailbox already exists");
}
return -1;
}
/* if dovecot-shared exists in the root dir, copy it to the
created mailbox */
}
return 0;
}
const char *name)
{
int count;
return -1;
}
return -1;
}
/* rename the .maildir into ..DOVECOT-TRASH which marks it as being
deleted. delete indexes before the actual maildir. this way we
never see partially deleted mailboxes. */
return -1;
}
/* 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
can't really help that. */
"unlink_directory(%s) failed: %m", index_dir);
return -1;
}
}
/* absolute maildir path, delete the directory directly
without any renaming */
} else {
count = 0;
/* EBUSY is given by some NFS implementations */
return -1;
}
/* already existed, delete it and try again */
"unlink_directory(%s) failed: %m",
dest);
return -1;
}
count++;
}
}
"unlink_directory(%s) failed: %m", dest);
/* it's already renamed to ..dir, which means it's deleted
as far as client is concerned. Report success. */
}
return 0;
}
{
return 0;
/* Rename it's index. */
"rename(%s, %s) failed: %m",
return -1;
}
return 0;
}
{
struct mailbox_list_context *ctx;
struct mailbox_list *list;
const char *const *names;
unsigned int i, count;
int ret;
ret = 0;
/* first get a list of the subfolders and save them to memory, because
we can't rely on readdir() not skipping files while the directory
is being modified. this doesn't protect against modifications by
other processes though. */
const char *name;
}
if (maildir_mailbox_list_deinit(ctx) < 0) {
ret = -1;
count = 0;
} else {
}
for (i = 0; i < count; i++) {
t_push();
/* FIXME: it's possible to merge two folders if either one of
them doesn't have existing root folder. We could check this
but I'm not sure if it's worth it. It could be even
considered as a feature.
Anyway, the bug with merging is that if both folders have
identically named subfolder they conflict. Just ignore those
and leave them under the old folder. */
ret = 1;
else {
"rename(%s, %s) failed: %m",
ret = -1;
t_pop();
break;
}
t_pop();
}
return ret;
}
{
int ret;
bool found;
return -1;
}
"Renaming INBOX isn't supported.");
return -1;
}
/* NOTE: it's possible to rename a nonexisting folder which has
subfolders. In that case we should ignore the rename() error. */
if (ret < 0)
return -1;
return -1;
}
return 0;
}
"Target mailbox already exists");
return -1;
} else {
return -1;
}
}
{
const char *path;
}
const char *name,
enum mailbox_name_status *status)
{
const char *path;
return 0;
}
return 0;
}
return 0;
}
return 0;
} else {
path);
return -1;
}
}
{
int ret = 0;
/*FIXME:if (!maildir_try_flush_dirty_flags(ibox->index, TRUE)) {
mail_storage_set_index_error(ibox);
ret = -1;
}*/
return ret;
}
static void
{
return;
}
}
struct mail_storage maildir_storage = {
{
}
};
struct mailbox maildir_mailbox = {
{
}
};