maildir-storage.c revision 4673afe816ffbca769585e4518e9b3c3d72e95dd
/* Copyright (C) 2002-2006 Timo Sirainen */
#include "lib.h"
#include "ioloop.h"
#include "array.h"
#include "hostpid.h"
#include "home-expand.h"
#include "mkdir-parents.h"
#include "unlink-directory.h"
#include "maildir-storage.h"
#include "maildir-uidlist.h"
#include "maildir-keywords.h"
#include "maildir-sync.h"
#include "index-mail.h"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
/* How often to touch the uidlist lock file when using KEEP_LOCKED flag */
#define MAILDIR_PLUSPLUS_DRIVER_NAME "maildir++"
#define MAILDIR_SUBFOLDER_FILENAME "maildirfolder"
struct rename_context {
bool found;
const char *newname;
};
extern struct mail_storage maildir_storage;
extern struct mailbox maildir_mailbox;
static const char *strip_tail_slash(const char *path)
{
else
return path;
}
static const char *strip_tail_slash_and_cut(const char *path)
{
}
static int
{
if ((flags & MAIL_STORAGE_FLAG_NO_AUTODETECTION) != 0) {
i_error("maildir: root directory not given");
return -1;
}
/* 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");
}
} else {
/* <Maildir> [:INBOX=<dir>] [:INDEX=<dir>] [:CONTROL=<dir>] */
if (debug)
if (p == NULL)
else {
do {
p++;
strip_tail_slash_and_cut(p+6);
strip_tail_slash_and_cut(p+6);
strip_tail_slash_and_cut(p+8);
}
p = strchr(p, ':');
} while (p != NULL);
}
}
if (debug)
i_info("maildir: couldn't find root dir");
return -1;
}
return 0;
}
static struct mail_storage *
enum mail_storage_flags flags,
enum file_lock_method lock_method)
{
struct maildir_storage *storage;
struct index_storage *istorage;
struct mailbox_list_settings list_set;
struct mailbox_list *list;
const char *error;
return NULL;
/* normally the maildir is created in verify_inbox() */
if ((flags & MAIL_STORAGE_FLAG_NO_AUTOCREATE) != 0) {
i_error("stat(%s) failed: %m",
}
return NULL;
}
}
return NULL;
}
/* put the temp files into tmp/ directory preferrably */
}
}
{
}
{
const char *path;
if (debug)
return FALSE;
}
if (debug)
return FALSE;
}
return TRUE;
}
static const char *
{
const char *root_dir;
return NULL;
MAILDIR_PLUSPLUS_DRIVER_NAME) != 0) {
/* Not maildir++ driver. Don't use this trick. */
return NULL;
}
}
{
if (verify) {
return 0;
"stat(%s) failed: %m", dir);
return -1;
}
}
if (!verify)
return -1;
} else {
"mkdir(%s) failed: %m", dir);
return -1;
}
}
return 0;
}
/* create or fix maildir, ignore if it already exists */
{
const char *path;
return -1;
return -1;
/* if tmp/ directory exists, we need to clean it up once in a while */
/* the directory should be empty. we won't do anything
until ctime changes. */
/* time to scan */
}
return -1;
} else {
return -1;
}
return 0;
}
{
if (*index_dir == '\0')
return 0;
return 0;
name);
"mkdir(%s) failed: %m", dir);
return -1;
}
return 0;
}
{
return 0;
name);
"mkdir(%s) failed: %m", dir);
return -1;
}
return 0;
}
{
const char *path;
return -1;
return -1;
return -1;
return 0;
}
{
}
static void maildir_lock_touch_timeout(void *context)
{
}
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)
index_dir = "";
/* for shared mailboxes get the create mode from the
permissions of dovecot-shared file. */
if (shared)
if (!shared) {
} else {
}
mailbox_close(&box);
return NULL;
}
mbox);
}
}
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;
}
}
{
const char *path;
int fd;
/* add the execute bit if either read or write bit is set */
"Mailbox already exists");
}
return -1;
}
}
if (fd == -1) {
return -1;
}
"fchown(%s) failed: %m", path);
}
return 0;
}
const char *name,
bool directory __attr_unused__)
{
int fd;
return -1;
}
/* if dovecot-shared exists in the root dir, create the mailbox using
its permissions and gid, and copy the dovecot-shared inside it. */
}
"Mailbox already exists");
}
return -1;
}
/* Maildir++ spec want that maildirfolder named file is created for
all subfolders. */
if (fd == -1)
else
return 0;
}
const char *name)
{
int count;
return -1;
}
return -1;
}
/* check if the mailbox actually exists */
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
that can't really be helped. */
/* if there's a separate index directory, delete it before the actual
maildir. this way we never see partially deleted mailboxes. */
"unlink_directory(%s) failed: %m", index_dir);
return -1;
}
}
"unlink_directory(%s) failed: %m", control_dir);
return -1;
}
}
/* absolute maildir path, delete the directory directly
without any renaming */
} else {
/* rename the .maildir into ..DOVECOT-TRASH which atomically
marks it as being deleted. If we die before deleting the
..DOVECOT-TRASH directory, it gets deleted the next time
mailbox listing sees it. */
count = 0;
if (!EDESTDIREXISTS(errno)) {
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 the client is concerned. Report success. */
}
return 0;
}
enum mailbox_list_path_type type,
{
return 0;
return -1;
}
return 0;
}
{
struct mailbox_list_iterate_context *iter;
struct mailbox_info *info;
ARRAY_DEFINE(names_arr, const char *);
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 (mailbox_list_iter_deinit(&iter) < 0) {
ret = -1;
} 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 {
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;
}
if (EDESTDIREXISTS(errno)) {
"Target mailbox already exists");
return -1;
} else {
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;
}
}
static int
enum mailbox_info_flags *flags,
enum mailbox_list_file_type type)
{
int ret;
MAILDIR_PLUSPLUS_DRIVER_NAME) == 0) {
const char *path;
/* this directory is in the middle of being deleted,
or the process trying to delete it had died.
delete it ourself if it's been there longer than
one hour. */
t_push();
t_pop();
return 0;
}
switch (type) {
/* all directories are valid maildirs */
return 1;
/* non-directories are not */
return 0;
/* need to check with stat() to be sure */
break;
}
/* Check files beginning with .nfs always because they may be
temporary files created by the kernel */
const char *path;
t_push();
t_pop();
if (ret == 0)
} else {
ret = 1;
}
return ret;
}
static void maildir_class_init(void)
{
}
static void maildir_class_deinit(void)
{
}
struct mail_storage maildir_storage = {
{
}
};
struct mailbox maildir_mailbox = {
{
}
};