]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
Index opening rewrites. We don't try to support .imap.index-<hostname> style
authorTimo Sirainen <tss@iki.fi>
Sun, 23 Feb 2003 21:06:57 +0000 (23:06 +0200)
committerTimo Sirainen <tss@iki.fi>
Sun, 23 Feb 2003 21:06:57 +0000 (23:06 +0200)
indexes anymore. They just made things more difficult, and it's really not a
good idea to use index files via NFS anyway.

Added support for :INDEX=MEMORY in MAIL env to disable using index files.
Also if we can't open or create index file for any reason, we now fallback
to in-memory indexes. Before we fallbacked only with out of disk space
errors.

If .customflags can't be created, we still work now by not allowing to
create new custom flags.

--HG--
branch : HEAD

23 files changed:
doc/index.txt
doc/mail-storages.txt
dovecot-example.conf
src/lib-index/Makefile.am
src/lib-index/mail-custom-flags.c
src/lib-index/mail-index-compress.c
src/lib-index/mail-index-data.c
src/lib-index/mail-index-open.c
src/lib-index/mail-index-util.c
src/lib-index/mail-index.c
src/lib-index/mail-index.h
src/lib-index/mail-lockdir.c [deleted file]
src/lib-index/mail-lockdir.h [deleted file]
src/lib-index/mail-modifylog.c
src/lib-index/mail-tree.c
src/lib-index/maildir/maildir-index.c
src/lib-index/mbox/mbox-index.c
src/lib-storage/index/index-storage.c
src/lib-storage/index/maildir/maildir-storage.c
src/lib-storage/index/mbox/mbox-storage.c
src/master/mail-process.c
src/master/master-settings.c
src/master/master-settings.h

index 395c454b549b991547b41624a08274f8eb366cde..f82c2cebfe7e46c79d2b92cce6e05836c1806a3a 100644 (file)
@@ -9,12 +9,6 @@ sizes. That information is saved into index file's "compatibility" fields.
 No attempt is made to deal with incompatible index files, they're either
 overwritten or new files are created.
 
-Index file names begin with ".imap.index" or ".imap.index-<hostname>". The
-first form is used by default, the second when first is found to be
-incompatible. If the second is also incompatible, it's simply overwritten.
-This should allow us to be NFS-safe in an environment with multiple
-different computer architectures.
-
 Indexes are bound to each others by "indexid" field in headers. If they
 don't match, the file is assumed to be corrupted and will be rebuilt.
 
index d24438d0bece83d738bac3236d53fc4d49937fd2..71f4ecd5636b56b1c995a27cd55993be19a18de6 100644 (file)
@@ -53,6 +53,11 @@ mailboxes.
 Adding :INDEX=<dir> to MAIL environment overrides the default location. The
 given directory must exist.
 
+It's also possible to disable index files by building them into memory.
+They're also automatically built into memory if the index files can't be
+opened or created for some reason (eg. out of disk space). To disable
+indexes always, add :INDEX=MEMORY to MAIL environment.
+
 
 Detecting what to use
 ---------------------
index 50bf6aaf358b0081aa117f78dc15b19511234eb7..bf39456fa23504e454d84e3900d15a214d4cf413 100644 (file)
@@ -294,12 +294,6 @@ login = pop3
 # lock file after this many seconds.
 #mbox_dotlock_change_timeout = 30
 
-# If main index file is incompatible with us, should we overwrite it or
-# create a new index with another name. Unless you are running Dovecot in
-# multiple computers with different architectures accessing the same
-# mailboxes (eg. via NFS), it's safe to set this "yes".
-#overwrite_incompatible_index = no
-
 # umask to use for mail files and directories
 #umask = 0077
 
index 314d6bc6889f2fec89a7d9660346796d4198d1b2..86eb73bd7326a9f7f56950ea27b4ccb6b48926e5 100644 (file)
@@ -17,7 +17,6 @@ libstorage_index_a_SOURCES = \
         mail-index-update.c \
         mail-index-update-cache.c \
         mail-index-util.c \
-        mail-lockdir.c \
        mail-modifylog.c \
        mail-tree.c \
        mail-tree-redblack.c
@@ -27,6 +26,5 @@ noinst_HEADERS = \
        mail-index.h \
         mail-index-data.h \
         mail-index-util.h \
-        mail-lockdir.h \
        mail-modifylog.h \
        mail-tree.h
index 6d2c9c8f26bce1377ca0f047446b20d09f888632..3dd979162b7c07af69273ef1cd2fbc700624014e 100644 (file)
@@ -9,9 +9,10 @@
 #include "mail-index-util.h"
 #include "mail-custom-flags.h"
 
+#include <ctype.h>
 #include <unistd.h>
 #include <fcntl.h>
-#include <ctype.h>
+#include <sys/stat.h>
 
 /* Header is simply a counter which is increased every time the file is
    updated. This allows other processes to easily notice if there's been
@@ -44,6 +45,11 @@ static int index_cf_set_syscall_error(struct mail_custom_flags *mcf,
 {
        i_assert(function != NULL);
 
+       if (errno == ENOSPC) {
+               mcf->index->nodiskspace = TRUE;
+               return FALSE;
+       }
+
        index_set_error(mcf->index, "%s failed with custom flags file %s: %m",
                        function, mcf->filepath);
        return FALSE;
@@ -69,8 +75,8 @@ static int update_mmap(struct mail_custom_flags *mcf)
 static int custom_flags_init(struct mail_custom_flags *mcf)
 {
        static char buf[HEADER_SIZE] = "0000\n";
+       struct stat st;
        int failed;
-       off_t pos;
 
        if (!lock_file(mcf, F_WRLCK))
                return FALSE;
@@ -78,22 +84,15 @@ static int custom_flags_init(struct mail_custom_flags *mcf)
        failed = FALSE;
 
        /* make sure it's still empty after locking */
-       pos = lseek(mcf->fd, 0, SEEK_END);
-       if (pos >= 0 && pos < HEADER_SIZE)
-               pos = lseek(mcf->fd, 0, SEEK_SET);
-
-       if (pos < 0) {
-               index_cf_set_syscall_error(mcf, "lseek()");
-               failed = TRUE;
-       }
-
-       /* write the header - it's a 4 byte counter as hex */
-       if (!failed && write_full(mcf->fd, buf, HEADER_SIZE) < 0) {
-               if (errno == ENOSPC)
-                       mcf->index->nodiskspace = TRUE;
-
-               index_cf_set_syscall_error(mcf, "write_full()");
+       if (fstat(mcf->fd, &st) < 0) {
+               index_cf_set_syscall_error(mcf, "fstat()");
                failed = TRUE;
+       } else if (st.st_size < HEADER_SIZE) {
+               /* write the header - it's a 4 byte counter as hex */
+               if (write_full(mcf->fd, buf, HEADER_SIZE) < 0) {
+                       index_cf_set_syscall_error(mcf, "write_full()");
+                       failed = TRUE;
+               }
        }
 
        if (!lock_file(mcf, F_UNLCK))
@@ -183,6 +182,11 @@ static int custom_flags_check_sync(struct mail_custom_flags *mcf)
                if (mcf->lock_type == F_RDLCK)
                        (void)lock_file(mcf, F_UNLCK);
 
+               if (lseek(mcf->fd, 0, SEEK_SET) < 0) {
+                       index_cf_set_syscall_error(mcf, "lseek()");
+                       return FALSE;
+               }
+
                if (!custom_flags_init(mcf))
                        return FALSE;
 
@@ -200,9 +204,13 @@ static int lock_file(struct mail_custom_flags *mcf, int type)
        if (mcf->lock_type == type)
                return TRUE;
 
-       /* FIXME: possibility to use .lock file instead */
-       if (file_wait_lock(mcf->fd, type) <= 0)
-               return index_cf_set_syscall_error(mcf, "file_wait_lock()");
+       if (mcf->fd != -1) {
+               /* FIXME: possibility to use .lock file instead */
+               if (file_wait_lock(mcf->fd, type) <= 0) {
+                       index_cf_set_syscall_error(mcf, "file_wait_lock()");
+                       return FALSE;
+               }
+       }
 
        mcf->lock_type = type;
 
@@ -230,13 +238,14 @@ int mail_custom_flags_open_or_create(struct mail_index *index)
        const char *path;
        int fd;
 
-       path = t_strconcat(index->dir, "/", CUSTOM_FLAGS_FILE_NAME, NULL);
-       fd = open(path, O_RDWR | O_CREAT, 0660);
-       if (fd == -1) {
-               if (errno == ENOSPC)
-                       index->nodiskspace = TRUE;
-
-               return index_file_set_syscall_error(index, path, "open()");
+       path = t_strconcat(index->custom_flags_dir, "/",
+                          CUSTOM_FLAGS_FILE_NAME, NULL);
+       if (path == NULL)
+               fd = -1;
+       else {
+               fd = open(path, O_RDWR | O_CREAT, 0660);
+               if (fd == -1)
+                       index_file_set_syscall_error(index, path, "open()");
        }
 
        mcf = i_new(struct mail_custom_flags, 1);
@@ -244,23 +253,26 @@ int mail_custom_flags_open_or_create(struct mail_index *index)
        mcf->filepath = i_strdup(path);
        mcf->fd = fd;
 
-       if (!update_mmap(mcf)) {
-               mail_custom_flags_free(mcf);
-               return FALSE;
-       }
+       if (fd != -1) {
+               if (!update_mmap(mcf)) {
+                       (void)close(mcf->fd);
+                       mcf->fd = -1;
+               }
 
-       if (mcf->mmap_length < HEADER_SIZE) {
-               /* we just created it, write the header */
-               mcf->syncing = TRUE;
-               if ((!custom_flags_init(mcf) || !update_mmap(mcf)) &&
-                   !index->nodiskspace) {
-                       mail_custom_flags_free(mcf);
-                       return FALSE;
+               if (mcf->mmap_length < HEADER_SIZE) {
+                       /* we just created it, write the header */
+                       mcf->syncing = TRUE;
+                       if (!custom_flags_init(mcf) || !update_mmap(mcf)) {
+                               (void)close(mcf->fd);
+                               mcf->fd = -1;
+                       }
+                       mcf->syncing = FALSE;
                }
-               mcf->syncing = FALSE;
-               mcf->noupdate = index->nodiskspace;
        }
 
+       mcf->noupdate = mcf->fd == -1;
+       mcf->index->allow_new_custom_flags = mcf->fd != -1;
+
        custom_flags_sync(mcf);
 
        index->custom_flags = mcf;
@@ -279,8 +291,10 @@ void mail_custom_flags_free(struct mail_custom_flags *mcf)
                        index_cf_set_syscall_error(mcf, "munmap()");
        }
 
-       if (close(mcf->fd) < 0)
-               index_cf_set_syscall_error(mcf, "close()");
+       if (mcf->fd != -1) {
+               if (close(mcf->fd) < 0)
+                       index_cf_set_syscall_error(mcf, "close()");
+       }
 
        i_free(mcf->filepath);
        i_free(mcf);
index c145cc276255a372e127c92436b9568de0da8b03..492b94e6eac9b0eca9577724847aad3b54cbcf75 100644 (file)
@@ -132,9 +132,6 @@ static int mail_index_copy_data(struct mail_index *index,
        memset(&data_hdr, 0, sizeof(data_hdr));
        data_hdr.indexid = index->indexid;
        if (write_full(fd, &data_hdr, sizeof(data_hdr)) < 0) {
-               if (errno == ENOSPC)
-                       index->nodiskspace = TRUE;
-
                index_file_set_syscall_error(index, path, "write_full()");
                return FALSE;
        }
@@ -164,9 +161,6 @@ static int mail_index_copy_data(struct mail_index *index,
 
                if (write_full(fd, mmap_data + rec->data_position,
                               rec_hdr->data_size) < 0) {
-                       if (errno == ENOSPC)
-                               index->nodiskspace = TRUE;
-
                        index_file_set_syscall_error(index, path,
                                                     "write_full()");
                        return FALSE;
@@ -207,11 +201,8 @@ int mail_index_compress_data(struct mail_index *index)
                return FALSE;
 
        fd = mail_index_create_temp_file(index, &temppath);
-       if (fd == -1) {
-               if (errno == ENOSPC)
-                       index->nodiskspace = TRUE;
+       if (fd == -1)
                return FALSE;
-       }
 
        failed = !mail_index_copy_data(index, fd, temppath);
 
index c677f907f89c94cdbb6caa5f3b992029320c76da..c1f9a88892c7912405b1261f08c435e45a74390e 100644 (file)
@@ -66,6 +66,11 @@ static int index_data_set_syscall_error(struct mail_index_data *data,
 {
        i_assert(function != NULL);
 
+       if (errno == ENOSPC) {
+               data->index->nodiskspace = TRUE;
+               return FALSE;
+       }
+
        index_set_error(data->index, "%s failed with index data file %s: %m",
                        function, data->filepath);
        return FALSE;
@@ -243,68 +248,52 @@ int mail_index_data_open(struct mail_index *index)
        return TRUE;
 }
 
-static const char *init_data_file(struct mail_index *index,
-                                 struct mail_index_data_header *hdr,
-                                 int fd, const char *temppath)
+static int mail_index_data_init(struct mail_index *index,
+                               struct mail_index_data_header *hdr,
+                               const char *path, int fd)
 {
-       const char *realpath;
-
        if (write_full(fd, hdr, sizeof(*hdr)) < 0) {
-               index_file_set_syscall_error(index, temppath, "write_full()");
-               return NULL;
+               index_file_set_syscall_error(index, path, "write_full()");
+               return FALSE;
        }
 
        if (file_set_size(fd, INDEX_DATA_INITIAL_SIZE) < 0) {
-               index_file_set_syscall_error(index, temppath,
-                                            "file_set_size()");
-               return NULL;
-       }
-
-       /* move temp file into .data file, deleting old one
-          if it already exists */
-       realpath = t_strconcat(index->filepath, DATA_FILE_PREFIX, NULL);
-       if (rename(temppath, realpath) < 0) {
-               index_set_error(index, "rename(%s, %s) failed: %m",
-                               temppath, realpath);
-               return NULL;
+               index_file_set_syscall_error(index, path, "file_set_size()");
+               return FALSE;
        }
 
-       return realpath;
+       return TRUE;
 }
 
 int mail_index_data_create(struct mail_index *index)
 {
         struct mail_index_data_header hdr;
        struct mail_index_data *data;
-       const char *temppath, *realpath;
+       const char *path;
        int fd;
 
+       i_assert(index->lock_type == MAIL_LOCK_EXCLUSIVE);
+
        memset(&hdr, 0, sizeof(struct mail_index_data_header));
        hdr.indexid = index->indexid;
        hdr.used_file_size = sizeof(struct mail_index_data_header);
 
-       realpath = NULL;
-
        /* we'll do anon-mmaping only if initially requested. if we fail
           because of out of disk space, we'll just let the main index code
           know it and fail. */
-       if (index->nodiskspace) {
+       if (INDEX_IS_IN_MEMORY(index)) {
                fd = -1;
+               path = NULL;
        } else {
-               fd = mail_index_create_temp_file(index, &temppath);
+               path = t_strconcat(index->filepath, DATA_FILE_PREFIX, NULL);
+               fd = open(path, O_RDWR | O_CREAT, 0660);
                if (fd == -1) {
-                       if (errno == ENOSPC)
-                               index->nodiskspace = TRUE;
+                       index_file_set_syscall_error(index, path, "open()");
                        return FALSE;
                }
 
-               realpath = init_data_file(index, &hdr, fd, temppath);
-               if (realpath == NULL) {
-                       if (errno == ENOSPC)
-                               index->nodiskspace = TRUE;
-
+               if (!mail_index_data_init(index, &hdr, path, fd)) {
                        (void)close(fd);
-                       (void)unlink(temppath);
                        return FALSE;
                }
        }
@@ -320,9 +309,11 @@ int mail_index_data_create(struct mail_index *index)
                data->mmap_used_length = data->header->used_file_size;
 
                data->anon_mmap = TRUE;
-               data->filepath = i_strdup("(in-memory index data)");
+               data->filepath =
+                       i_strdup_printf("(in-memory index data index for %s)",
+                                       index->mailbox_path);
        } else {
-               data->filepath = i_strdup(realpath);
+               data->filepath = i_strdup(path);
        }
 
        data->index = index;
@@ -360,20 +351,14 @@ int mail_index_data_reset(struct mail_index_data *data)
                return TRUE;
        }
 
-       if (file_set_size(data->fd, INDEX_DATA_INITIAL_SIZE) < 0) {
-               if (errno == ENOSPC)
-                       data->index->nodiskspace = TRUE;
+       if (file_set_size(data->fd, INDEX_DATA_INITIAL_SIZE) < 0)
                return index_data_set_syscall_error(data, "file_set_size()");
-       }
 
        if (lseek(data->fd, 0, SEEK_SET) < 0)
                return index_data_set_syscall_error(data, "lseek()");
 
-       if (write_full(data->fd, &hdr, sizeof(hdr)) < 0) {
-               if (errno == ENOSPC)
-                       data->index->nodiskspace = TRUE;
+       if (write_full(data->fd, &hdr, sizeof(hdr)) < 0)
                return index_data_set_syscall_error(data, "write_full()");
-       }
 
        data->modified = FALSE;
        data->fsynced = FALSE;
@@ -440,11 +425,8 @@ static int mail_index_data_grow(struct mail_index_data *data, size_t size)
        if (pos < (off_t)sizeof(struct mail_index_data_header))
                return index_data_set_corrupted(data, "Header is missing");
 
-       if (file_set_size(data->fd, (off_t)new_fsize) < 0) {
-               if (errno == ENOSPC)
-                       data->index->nodiskspace = TRUE;
+       if (file_set_size(data->fd, (off_t)new_fsize) < 0)
                return index_data_set_syscall_error(data, "file_set_size()");
-       }
 
        return mmap_update(data, 0, 0);
 }
index 9f9a7418884fc55d9ee10fbc310bf45d755584a1..cf938e3575802d5a379c9b539870f74878ec76cb 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2002 Timo Sirainen */
+/* Copyright (C) 2002-2003 Timo Sirainen */
 
 #include "lib.h"
 #include "ioloop.h"
@@ -12,7 +12,6 @@
 #include "mail-index-data.h"
 #include "mail-index-util.h"
 #include "mail-tree.h"
-#include "mail-lockdir.h"
 #include "mail-modifylog.h"
 #include "mail-custom-flags.h"
 
 #include <unistd.h>
 #include <fcntl.h>
 
-static const char *index_file_prefixes[] =
-       { "data", "tree", "log", "log.2", NULL };
-
-static int delete_index(const char *path)
-{
-       char tmp[PATH_MAX];
-       int i;
-
-       /* main index */
-       if (unlink(path) < 0)
-               return FALSE;
-
-       for (i = 0; index_file_prefixes[i] != NULL; i++) {
-               if (i_snprintf(tmp, sizeof(tmp), "%s.%s",
-                              path, index_file_prefixes[i]) < 0)
-                       return FALSE;
-
-               if (unlink(tmp) < 0)
-                       return FALSE;
-               i++;
-       }
-
-       return TRUE;
-}
-
-static int read_and_verify_header(int fd, struct mail_index_header *hdr,
-                                 int check_version)
-{
-       /* read the header */
-       if (lseek(fd, 0, SEEK_SET) != 0)
-               return FALSE;
-
-       if (read(fd, hdr, sizeof(*hdr)) != sizeof(*hdr))
-               return FALSE;
-
-       /* check the compatibility */
-       return hdr->compat_data[1] == MAIL_INDEX_COMPAT_FLAGS &&
-               hdr->compat_data[2] == sizeof(unsigned int) &&
-               hdr->compat_data[3] == sizeof(time_t) &&
-               hdr->compat_data[4] == sizeof(uoff_t) &&
-               hdr->compat_data[5] == MEM_ALIGN_SIZE &&
-               (!check_version || hdr->compat_data[0] == MAIL_INDEX_VERSION);
-}
-
-/* Returns TRUE if we're compatible with given index file. May delete the
-   file if it's from older version. */
-static int mail_check_compatible_index(struct mail_index *index,
-                                      const char *path)
-{
-        struct mail_index_header hdr;
-       int fd, compatible;
-
-       fd = open(path, O_RDONLY);
-       if (fd == -1) {
-               if (errno != ENOENT)
-                       index_file_set_syscall_error(index, path, "open()");
-               return FALSE;
-       }
-
-       compatible = read_and_verify_header(fd, &hdr, FALSE);
-       if (hdr.compat_data[0] != MAIL_INDEX_VERSION) {
-               /* version mismatch */
-               compatible = FALSE;
-               if (hdr.compat_data[0] < MAIL_INDEX_VERSION) {
-                       /* of older version, we don't need it anymore */
-                       (void)delete_index(path);
-               }
-       }
-
-       (void)close(fd);
-       return compatible;
-}
-
-/* Returns a file name of compatible index */
-static const char *mail_find_index(struct mail_index *index)
-{
-       const char *name;
-       char path[PATH_MAX];
-
-       hostpid_init();
-
-       /* first try .imap.index-<hostname> */
-       name = t_strconcat(INDEX_FILE_PREFIX "-", my_hostname, NULL);
-       if (str_path(path, sizeof(path), index->dir, name) == 0 &&
-           mail_check_compatible_index(index, path))
-               return name;
-
-       /* then try the generic .imap.index */
-       name = INDEX_FILE_PREFIX;
-       if (str_path(path, sizeof(path), index->dir, name) == 0 &&
-           mail_check_compatible_index(index, path))
-               return name;
-
-       return NULL;
-}
-
-static int mail_index_open_init(struct mail_index *index, int update_recent)
+static int mail_index_open_init(struct mail_index *index,
+                               enum mail_index_open_flags flags)
 {
        struct mail_index_header *hdr;
 
        hdr = index->header;
 
        /* update \Recent message counters */
-       if (update_recent && hdr->last_nonrecent_uid != hdr->next_uid-1) {
+       if ((flags & MAIL_INDEX_OPEN_FLAG_UPDATE_RECENT) != 0 &&
+           hdr->last_nonrecent_uid != hdr->next_uid-1) {
                /* keep last_recent_uid to next_uid-1 */
                if (index->lock_type == MAIL_LOCK_SHARED) {
                        if (!index->set_lock(index, MAIL_LOCK_UNLOCK))
@@ -157,24 +62,24 @@ static int mail_index_open_init(struct mail_index *index, int update_recent)
 }
 
 static int index_open_and_fix(struct mail_index *index,
-                             int update_recent, int fast)
+                             enum mail_index_open_flags flags)
 {
-       int rebuild;
-
-       if (!mail_index_mmap_update(index))
-               return FALSE;
-
-       rebuild = FALSE;
-
        /* open/create the index files */
-       if (!mail_index_data_open(index)) {
-               if ((index->set_flags & MAIL_INDEX_FLAG_REBUILD) == 0)
-                       return FALSE;
+       if ((flags & _MAIL_INDEX_OPEN_FLAG_CREATING) == 0) {
+               if (!mail_index_data_open(index)) {
+                       if ((index->set_flags & MAIL_INDEX_FLAG_REBUILD) == 0)
+                               return FALSE;
 
-               /* data file is corrupted, need to rebuild index */
-               rebuild = TRUE;
-               index->set_flags = 0;
+                       /* data file is corrupted, need to rebuild index */
+                       flags |= _MAIL_INDEX_OPEN_FLAG_CREATING;
+                       index->set_flags = 0;
+                       index->inconsistent = FALSE;
+               }
+       }
 
+       if ((flags & _MAIL_INDEX_OPEN_FLAG_CREATING) != 0) {
+               if (!mail_index_set_lock(index, MAIL_LOCK_EXCLUSIVE))
+                       return FALSE;
                if (!mail_index_data_create(index))
                        return FALSE;
        }
@@ -184,20 +89,27 @@ static int index_open_and_fix(struct mail_index *index,
        if (!mail_custom_flags_open_or_create(index))
                return FALSE;
 
-       if (rebuild || (index->header->flags & MAIL_INDEX_FLAG_REBUILD)) {
-               /* index is corrupted, rebuild */
+       if ((flags & _MAIL_INDEX_OPEN_FLAG_CREATING) != 0 ||
+           (index->header->flags & MAIL_INDEX_FLAG_REBUILD) != 0) {
                if (!index->rebuild(index))
                        return FALSE;
 
-               /* no inconsistency problems while still opening
+               /* no inconsistency problems since we're still opening
                   the index */
                index->inconsistent = FALSE;
        }
 
-       if (!mail_tree_open_or_create(index))
-               return FALSE;
-       if (!mail_modifylog_open_or_create(index))
-               return FALSE;
+       if ((flags & _MAIL_INDEX_OPEN_FLAG_CREATING) == 0) {
+               if (!mail_tree_open_or_create(index))
+                       return FALSE;
+               if (!mail_modifylog_open_or_create(index))
+                       return FALSE;
+       } else {
+               if (!mail_tree_create(index))
+                       return FALSE;
+               if (!mail_modifylog_create(index))
+                       return FALSE;
+       }
 
        if (index->header->flags & MAIL_INDEX_FLAG_FSCK) {
                /* index needs fscking */
@@ -205,18 +117,12 @@ static int index_open_and_fix(struct mail_index *index,
                        return FALSE;
        }
 
-       if (!fast && (index->header->flags & MAIL_INDEX_FLAG_COMPRESS)) {
-               /* remove deleted blocks from index file */
-               if (!mail_index_compress(index))
-                       return FALSE;
-       }
-
-       if (index->header->flags & MAIL_INDEX_FLAG_REBUILD_TREE) {
+       if ((index->header->flags & MAIL_INDEX_FLAG_REBUILD_TREE) != 0) {
                if (!mail_tree_rebuild(index->tree))
                        return FALSE;
        }
 
-       /* sync ourself - before updating cache and compression which
+       /* sync ourself. do it before updating cache and compression which
           may happen because of this. */
        if (!index->sync_and_lock(index, MAIL_LOCK_SHARED, NULL))
                return FALSE;
@@ -229,262 +135,91 @@ static int index_open_and_fix(struct mail_index *index,
                        return FALSE;
        }
 
-       if (!fast && (index->header->flags & MAIL_INDEX_FLAG_CACHE_FIELDS)) {
-               /* need to update cached fields */
-               if (!mail_index_update_cache(index))
-                       return FALSE;
-       }
-
-       if (!fast && (index->header->flags & MAIL_INDEX_FLAG_COMPRESS_DATA)) {
-               /* remove unused space from index data file.
-                  keep after cache_fields which may move data
-                  and create unused space.. */
-               if (!mail_index_compress_data(index))
-                       return FALSE;
-       }
-
-       if (!mail_index_open_init(index, update_recent))
-               return FALSE;
-
-       return TRUE;
-}
+       if ((flags & MAIL_INDEX_OPEN_FLAG_FAST) == 0) {
+               if (index->header->flags & MAIL_INDEX_FLAG_COMPRESS) {
+                       /* remove deleted blocks from index file */
+                       if (!mail_index_compress(index))
+                               return FALSE;
+               }
 
-static int mail_index_verify_header(struct mail_index *index,
-                                   struct mail_index_header *hdr)
-{
-       /* if index is being created, we'll wait here until it's finished */
-       if (!mail_index_wait_lock(index, F_RDLCK))
-               return FALSE;
+               if (index->header->flags & MAIL_INDEX_FLAG_CACHE_FIELDS) {
+                       /* need to update cached fields */
+                       if (!mail_index_update_cache(index))
+                               return FALSE;
+               }
 
-       /* check the compatibility anyway just to be sure */
-       if (!read_and_verify_header(index->fd, hdr, TRUE)) {
-               index_set_error(index, "Non-compatible index file %s",
-                               index->filepath);
-               (void)mail_index_wait_lock(index, F_UNLCK);
-               return FALSE;
+               if (index->header->flags & MAIL_INDEX_FLAG_COMPRESS_DATA) {
+                       /* remove unused space from index data file.
+                          keep after cache updates which may move data
+                          and create unused space */
+                       if (!mail_index_compress_data(index))
+                               return FALSE;
+               }
        }
 
-       if (!mail_index_wait_lock(index, F_UNLCK))
+       if (!mail_index_open_init(index, flags))
                return FALSE;
 
        return TRUE;
 }
 
-static int mail_index_open_file(struct mail_index *index, const char *path,
-                               int update_recent, int fast)
+static int mail_index_read_header(struct mail_index *index,
+                                 struct mail_index_header *hdr)
 {
-        struct mail_index_header hdr;
-
-       /* the index file should already be checked that it exists and
-          we're compatible with it. */
+       ssize_t ret;
 
-       index->fd = open(path, O_RDWR);
-       if (index->fd == -1)
-               return index_file_set_syscall_error(index, path, "open()");
-       index->filepath = i_strdup(path);
-
-       if (!mail_index_verify_header(index, &hdr)) {
-               (void)close(index->fd);
-               index->fd = -1;
-
-               i_free(index->filepath);
-               index->filepath = NULL;
-               return FALSE;
+       ret = read(index->fd, hdr, sizeof(*hdr));
+       if (ret < 0) {
+               index_set_syscall_error(index, "read()");
+               return -1;
        }
 
-       index->indexid = hdr.indexid;
-
-       /* the shared lock set is just to make sure we drop exclusive lock */
-       if (!index_open_and_fix(index, update_recent, fast) ||
-           !index->set_lock(index, MAIL_LOCK_UNLOCK)) {
-               mail_index_close(index);
-               return FALSE;
+       if (ret != sizeof(*hdr)) {
+               /* missing data */
+               return 0;
        }
 
-       return TRUE;
+       return 1;
 }
 
-static int mail_index_init_new_file(struct mail_index *index,
-                                   struct mail_index_header *hdr,
-                                   const char *temp_path)
+static int mail_index_is_compatible(const struct mail_index_header *hdr)
 {
-       const char *index_path;
-       off_t fsize;
+       return hdr->compat_data[0] == MAIL_INDEX_VERSION &&
+               hdr->compat_data[1] == MAIL_INDEX_COMPAT_FLAGS &&
+               hdr->compat_data[2] == sizeof(unsigned int) &&
+               hdr->compat_data[3] == sizeof(time_t) &&
+               hdr->compat_data[4] == sizeof(uoff_t) &&
+               hdr->compat_data[5] == MEM_ALIGN_SIZE;
+}
 
-       /* set the index's path temporarily */
-       index->filepath = t_strdup_noconst(temp_path);
+static int mail_index_init_file(struct mail_index *index,
+                               struct mail_index_header *hdr)
+{
+       hdr->used_file_size = sizeof(*hdr) +
+               INDEX_MIN_RECORDS_COUNT * sizeof(struct mail_index_record);
 
-       if (write_full(index->fd, hdr, sizeof(struct mail_index_header)) < 0) {
-               index_set_syscall_error(index, "write_full()");
-               index->filepath = NULL;
+       if (lseek(index->fd, 0, SEEK_SET) < 0) {
+               index_set_syscall_error(index, "lseek()");
                return FALSE;
        }
 
-       fsize = sizeof(struct mail_index_header) +
-               INDEX_MIN_RECORDS_COUNT * sizeof(struct mail_index_record);
-       if (file_set_size(index->fd, fsize) < 0) {
-               index_set_syscall_error(index, "file_set_size()");
-               index->filepath = NULL;
+       if (write_full(index->fd, hdr, sizeof(*hdr)) < 0) {
+               index_set_syscall_error(index, "write_full()");
                return FALSE;
        }
 
-       if (mail_index_wait_lock(index, F_WRLCK) <= 0) {
-               index->filepath = NULL;
+       if (file_set_size(index->fd, (off_t)hdr->used_file_size) < 0) {
+               index_set_syscall_error(index, "file_set_size()");
                return FALSE;
        }
-       index->filepath = NULL;
 
-       /* move the temp index into the real one. we also need to figure
-          out what to call ourself on the way. */
-       index_path = t_strconcat(index->dir, "/"INDEX_FILE_PREFIX, NULL);
-       if (link(temp_path, index_path) == 0) {
-               if (unlink(temp_path) < 0) {
-                       /* doesn't really matter, log anyway */
-                       index_file_set_syscall_error(index, temp_path,
-                                                    "unlink()");
-               }
-       } else {
-               if (errno != EEXIST) {
-                       /* fatal error */
-                       index_set_error(index, "link(%s, %s) failed: %m",
-                                       temp_path, index_path);
-                       return FALSE;
-               }
-
-               if (getenv("OVERWRITE_INCOMPATIBLE_INDEX") != NULL) {
-                       /* don't try to support different architectures,
-                          just overwrite the index if it's already there. */
-               } else {
-                       /* fallback to .imap.index-hostname - we require each
-                          system to have a different hostname so it's safe to
-                          override previous index as well */
-                       hostpid_init();
-
-                       index_path = t_strconcat(index_path, "-",
-                                                my_hostname, NULL);
-               }
-
-               if (rename(temp_path, index_path) < 0) {
-                       index_set_error(index, "rename(%s, %s) failed: %m",
-                                       temp_path, index_path);
-                       return FALSE;
-               }
-       }
-
-       index->filepath = i_strdup(index_path);
        return TRUE;
 }
 
-static int mail_index_create(struct mail_index *index, int *dir_unlocked,
-                            int update_recent)
-{
-       struct mail_index_header hdr;
-       const char *path;
-       int nodiskspace;
-
-       *dir_unlocked = FALSE;
-
-       mail_index_init_header(index, &hdr);
-
-       if (index->nodiskspace) {
-               /* don't even bother trying to create it */
-       } else {
-               /* first create the index into temporary file. */
-               index->fd = mail_index_create_temp_file(index, &path);
-               if (index->fd != -1) {
-                       if (!mail_index_init_new_file(index, &hdr, path)) {
-                               int old_errno = errno;
-
-                               (void)close(index->fd);
-                               (void)unlink(path);
-                               index->fd = -1;
-
-                               errno = old_errno;
-                       }
-               }
-
-               if (index->fd == -1 && errno != ENOSPC) {
-                       /* fatal failure */
-                       return FALSE;
-               }
-       }
-
-       if (index->fd == -1) {
-               /* no space for index files, keep it in memory */
-               index->mmap_full_length = INDEX_FILE_MIN_SIZE;
-               index->mmap_base = mmap_anon(index->mmap_full_length);
-
-               memcpy(index->mmap_base, &hdr, sizeof(hdr));
-               index->header = index->mmap_base;
-               index->mmap_used_length = index->header->used_file_size;
-
-               index->anon_mmap = TRUE;
-               index->filepath = i_strdup("(in-memory index)");
-       }
-
-       index->indexid = hdr.indexid;
-
-       /* the fd is actually already locked, now we're just making it
-          clear to the indexing code. */
-       if (!index->set_lock(index, MAIL_LOCK_EXCLUSIVE)) {
-               mail_index_close(index);
-               return FALSE;
-       }
-
-       /* it's not good to keep the directory locked too long. our index file
-          is locked which is enough. */
-       if (!*dir_unlocked && mail_index_lock_dir(index, MAIL_LOCK_UNLOCK))
-               *dir_unlocked = TRUE;
-
-       do {
-               if (!mail_custom_flags_open_or_create(index))
-                       break;
-               if (!mail_index_data_create(index))
-                       break;
-
-               nodiskspace = index->nodiskspace;
-               if (!index->rebuild(index)) {
-                       if (!index->anon_mmap && index->nodiskspace) {
-                               /* we're out of disk space, keep it in
-                                  memory this time */
-                               mail_index_close(index);
-
-                                index->nodiskspace = TRUE;
-                               return mail_index_create(index, dir_unlocked,
-                                                        update_recent);
-                       }
-                       break;
-               }
-
-               /* rebuild() resets the nodiskspace variable */
-               index->nodiskspace = nodiskspace;
-
-               if (!mail_tree_create(index))
-                       break;
-               if (!mail_modifylog_create(index))
-                       break;
-
-               index->inconsistent = FALSE;
-
-               if (!mail_index_open_init(index, update_recent))
-                       break;
-
-               if (!index->set_lock(index, MAIL_LOCK_UNLOCK))
-                       break;
-
-               return TRUE;
-       } while (0);
-
-       (void)index->set_lock(index, MAIL_LOCK_UNLOCK);
-
-       mail_index_close(index);
-       return FALSE;
-}
-
 void mail_index_init_header(struct mail_index *index,
                            struct mail_index_header *hdr)
 {
-       memset(hdr, 0, sizeof(struct mail_index_header));
+       memset(hdr, 0, sizeof(*hdr));
        hdr->compat_data[0] = MAIL_INDEX_VERSION;
        hdr->compat_data[1] = MAIL_INDEX_COMPAT_FLAGS;
        hdr->compat_data[2] = sizeof(unsigned int);
@@ -516,73 +251,136 @@ void mail_index_init(struct mail_index *index, const char *dir)
        size_t len;
 
        index->fd = -1;
-       index->dir = i_strdup(dir);
 
-       len = strlen(index->dir);
-       if (index->dir[len-1] == '/')
-               index->dir[len-1] = '\0';
+       if (dir != NULL) {
+               index->dir = i_strdup(dir);
+
+               len = strlen(index->dir);
+               if (index->dir[len-1] == '/')
+                       index->dir[len-1] = '\0';
+       }
 
        index->mail_read_mmaped = getenv("MAIL_READ_MMAPED") != NULL;
 }
 
-int mail_index_open(struct mail_index *index, int update_recent, int fast)
+static int mail_index_create_memory(struct mail_index *index,
+                                   enum mail_index_open_flags flags)
 {
-       const char *name, *path;
+       if ((flags & MAIL_INDEX_OPEN_FLAG_CREATE) == 0)
+               return FALSE;
 
-       i_assert(!index->opened);
+       flags |= _MAIL_INDEX_OPEN_FLAG_CREATING;
 
-       /* this isn't initialized anywhere else */
-       index->fd = -1;
+       index->mmap_full_length = INDEX_FILE_MIN_SIZE;
+       index->mmap_base = mmap_anon(index->mmap_full_length);
 
-       mail_index_cleanup_temp_files(index->dir);
+       mail_index_init_header(index, index->mmap_base);
+       index->header = index->mmap_base;
+       index->mmap_used_length = index->header->used_file_size;
 
-       name = mail_find_index(index);
-       if (name == NULL)
-               return FALSE;
+       index->anon_mmap = TRUE;
+       index->lock_type = MAIL_LOCK_EXCLUSIVE;
+       index->indexid = index->header->indexid;
+       index->filepath = i_strdup_printf("(in-memory index for %s)",
+                                         index->mailbox_path);
 
-       path = t_strconcat(index->dir, "/", name, NULL);
-       if (!mail_index_open_file(index, path, update_recent, fast))
+       if (!index_open_and_fix(index, flags)) {
+               mail_index_close(index);
                return FALSE;
+       }
 
-       index->opened = TRUE;
        return TRUE;
 }
 
-int mail_index_open_or_create(struct mail_index *index,
-                             int update_recent, int fast)
+int mail_index_open(struct mail_index *index, enum mail_index_open_flags flags)
 {
-       int failed, dir_unlocked;
+        struct mail_index_header hdr;
+       const char *path;
+       int ret;
 
        i_assert(!index->opened);
 
+       if (index->dir == NULL)
+               return mail_index_create_memory(index, flags);
+
        mail_index_cleanup_temp_files(index->dir);
 
-       if (index->open(index, update_recent, fast))
-               return TRUE;
+       /* open/create the file */
+        path = t_strconcat(index->dir, "/", INDEX_FILE_PREFIX, NULL);
+       if ((flags & MAIL_INDEX_OPEN_FLAG_CREATE) != 0)
+               index->fd = open(path, O_RDWR | O_CREAT, 0660);
+       else
+               index->fd = open(path, O_RDWR);
+       if (index->fd == -1) {
+               if (errno != ENOENT)
+                       index_file_set_syscall_error(index, path, "open()");
+               return mail_index_create_memory(index, flags);
+       }
+
+       index->filepath = i_strdup(path);
 
-       if (index->index_lock_timeout || index->mailbox_lock_timeout)
-               return FALSE;
+       for (;;) {
+               /* if index is being created, we'll wait here until it's
+                  finished */
+               if ((flags & _MAIL_INDEX_OPEN_FLAG_CREATING) == 0)
+                       index->lock_type = MAIL_LOCK_SHARED;
+               else
+                       index->lock_type = MAIL_LOCK_EXCLUSIVE;
+               if (!mail_index_wait_lock(index,
+                                         MAIL_LOCK_TO_FLOCK(index->lock_type)))
+                       break;
 
-       /* index wasn't found or it was broken. lock the directory and check
-          again, just to make sure we don't end up having two index files
-          due to race condition with another process. */
-       if (!mail_index_lock_dir(index, MAIL_LOCK_EXCLUSIVE))
-               return FALSE;
+               if ((ret = mail_index_read_header(index, &hdr)) < 0)
+                       break;
+
+               if (ret == 0 || !mail_index_is_compatible(&hdr)) {
+                       if ((flags & MAIL_INDEX_OPEN_FLAG_CREATE) == 0)
+                               break;
+
+                       flags |= _MAIL_INDEX_OPEN_FLAG_CREATING;
+
+                       /* so, we're creating the index */
+                       if (index->lock_type != MAIL_LOCK_EXCLUSIVE) {
+                               /* have to get exclusive lock first */
+                               if (!mail_index_wait_lock(index, F_UNLCK))
+                                       break;
+                               continue;
+                       }
+
+                       mail_index_init_header(index, &hdr);
+                       if (!mail_index_init_file(index, &hdr))
+                               break;
+               }
+
+               index->indexid = hdr.indexid;
 
-       failed = FALSE;
-       if (index->open(index, update_recent, fast))
-               dir_unlocked = FALSE;
-       else if (!index->index_lock_timeout && !index->mailbox_lock_timeout) {
-               if (!mail_index_create(index, &dir_unlocked, update_recent))
-                       failed = TRUE;
+               if (!mail_index_mmap_update(index))
+                       break;
+
+               if (index->lock_type == MAIL_LOCK_SHARED) {
+                       /* we don't want to keep the shared lock while opening
+                          indexes. opening should work unlocked and some
+                          things want exclusive lock */
+                       if (!mail_index_wait_lock(index, F_UNLCK))
+                               break;
+                       index->lock_type = MAIL_LOCK_UNLOCK;
+               }
+
+               if (!index_open_and_fix(index, flags) ||
+                   !index->set_lock(index, MAIL_LOCK_UNLOCK)) {
+                       mail_index_close(index);
+                       return mail_index_create_memory(index, flags);
+               }
+
+               index->opened = TRUE;
+               return TRUE;
        }
 
-       if (!dir_unlocked && !mail_index_lock_dir(index, MAIL_LOCK_UNLOCK))
-               return FALSE;
+       (void)close(index->fd);
+       index->fd = -1;
 
-       if (failed)
-               return FALSE;
+       i_free(index->filepath);
+       index->filepath = NULL;
 
-       index->opened = TRUE;
-       return TRUE;
+       return mail_index_create_memory(index, flags);
 }
index 68d490e6475b42cec34e4e5ecce0c6f16ee90be2..bca9b64a5a75605b779f5491d65f4be9a0f7b213 100644 (file)
@@ -52,6 +52,11 @@ int index_set_syscall_error(struct mail_index *index, const char *function)
 {
        i_assert(function != NULL);
 
+       if (errno == ENOSPC) {
+               index->nodiskspace = TRUE;
+               return FALSE;
+       }
+
        index_set_error(index, "%s failed with index file %s: %m",
                        function, index->filepath);
        return FALSE;
@@ -63,6 +68,11 @@ int index_file_set_syscall_error(struct mail_index *index, const char *filepath,
        i_assert(filepath != NULL);
        i_assert(function != NULL);
 
+       if (errno == ENOSPC) {
+               index->nodiskspace = TRUE;
+               return FALSE;
+       }
+
        index_set_error(index, "%s failed with file %s: %m",
                        function, filepath);
 
@@ -100,8 +110,10 @@ int mail_index_create_temp_file(struct mail_index *index, const char **path)
        if (fd == -1) {
                if (errno == ENOSPC)
                        index->nodiskspace = TRUE;
-
-               index_set_error(index, "Can't create temp index %s: %m", *path);
+               else {
+                       index_set_error(index, "Can't create temp index %s: %m",
+                                       *path);
+               }
        }
 
        return fd;
index 4898fb57dd0a060b0f8fd277df0a87ee29d7af17..849b867ce62bdb0c8ab897f6fe715a7231fb9df6 100644 (file)
@@ -170,6 +170,11 @@ void mail_index_close(struct mail_index *index)
                 index->custom_flags = NULL;
        }
 
+       if (index->custom_flags_dir != NULL) {
+               i_free(index->custom_flags_dir);
+                index->custom_flags_dir = NULL;
+       }
+
        if (index->error != NULL) {
                i_free(index->error);
                index->error = NULL;
@@ -946,11 +951,8 @@ static int mail_index_grow(struct mail_index *index)
                return mmap_verify(index);
        }
 
-       if (file_set_size(index->fd, (off_t)pos) < 0) {
-               if (errno == ENOSPC)
-                       index->nodiskspace = TRUE;
+       if (file_set_size(index->fd, (off_t)pos) < 0)
                return index_set_syscall_error(index, "file_set_size()");
-       }
 
        /* file size changed, let others know about it too by changing
           sync_id in header. */
index 15ed37b68b4c386a1ab307424f27e8e7e7c88016..f7b6d91ea577374f5bce9df42886b41fba3de87f 100644 (file)
@@ -9,6 +9,18 @@
 
 #define INDEX_FILE_PREFIX ".imap.index"
 
+enum mail_index_open_flags {
+       /* Create index if it doesn't exist */
+       MAIL_INDEX_OPEN_FLAG_CREATE             = 0x01,
+       /* Update \Recent flag counters */
+       MAIL_INDEX_OPEN_FLAG_UPDATE_RECENT      = 0x02,
+       /* Compressing and cache updates are not performed */
+       MAIL_INDEX_OPEN_FLAG_FAST               = 0x04,
+
+       /* internal: we're creating the index */
+       _MAIL_INDEX_OPEN_FLAG_CREATING          = 0x10
+};
+
 enum mail_index_header_compat {
        MAIL_INDEX_COMPAT_LITTLE_ENDIAN = 0x01
 };
@@ -174,14 +186,11 @@ struct mail_index_data_record {
         (SIZEOF_MAIL_INDEX_DATA + (rec)->full_field_size)
 
 struct mail_index {
-       /* If fast is TRUE, compressing and cache updates are not performed.
-          Note that opening same index twice in the same process is a bad
+       /* Note that opening same index twice in the same process is a bad
           idea since they share the same file locks. As soon one of the
           indexes is closed, the locks in second index are dropped which
           especially hurts modify log since it keeps locks all the time. */
-       int (*open)(struct mail_index *index, int update_recent, int fast);
-       int (*open_or_create)(struct mail_index *index,
-                             int update_recent, int fast);
+       int (*open)(struct mail_index *index, enum mail_index_open_flags flags);
 
        /* Free index from memory. */
        void (*free)(struct mail_index *index);
@@ -358,6 +367,7 @@ struct mail_index {
        char *dir; /* directory where to place the index files */
        char *filepath; /* index file path */
        char *mailbox_path; /* file/directory for mailbox location */
+       char *custom_flags_dir; /* destination for .customflags file */
        enum mail_data_field default_cache_fields, never_cache_fields;
        unsigned int indexid;
        unsigned int sync_id;
@@ -407,6 +417,7 @@ struct mail_index {
        unsigned int inconsistent:1;
        unsigned int nodiskspace:1;
        unsigned int index_lock_timeout:1;
+       unsigned int allow_new_custom_flags:1;
        unsigned int mailbox_lock_timeout:1;
 };
 
@@ -420,16 +431,14 @@ struct mail_index {
    members.. */
 #define MAIL_INDEX_PRIVATE_FILL \
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
-       0, 0, 0, 0, 0, { 0, 0, 0 }, 0, 0, 0, \
+       0, 0, 0, 0, 0, 0, { 0, 0, 0 }, 0, 0, \
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
-       0, 0
+       0, 0, 0, 0
 #endif
 
 /* defaults - same as above but prefixed with mail_index_. */
-int mail_index_open(struct mail_index *index, int update_recent, int fast);
-int mail_index_open_or_create(struct mail_index *index,
-                             int update_recent, int fast);
+int mail_index_open(struct mail_index *index, enum mail_index_open_flags flags);
 int mail_index_set_lock(struct mail_index *index,
                        enum mail_lock_type lock_type);
 int mail_index_try_lock(struct mail_index *index,
@@ -567,4 +576,7 @@ int mail_index_truncate(struct mail_index *index);
         ((lock_type) == MAIL_LOCK_EXCLUSIVE ? F_WRLCK : \
                (lock_type) == MAIL_LOCK_SHARED ? F_RDLCK : F_UNLCK)
 
+#define INDEX_IS_IN_MEMORY(index) \
+       ((index)->anon_mmap)
+
 #endif
diff --git a/src/lib-index/mail-lockdir.c b/src/lib-index/mail-lockdir.c
deleted file mode 100644 (file)
index e266af2..0000000
+++ /dev/null
@@ -1,164 +0,0 @@
-/* Copyright (C) 2002 Timo Sirainen */
-
-#include "lib.h"
-#include "hostpid.h"
-#include "unlink-lockfiles.h"
-#include "mail-index.h"
-#include "mail-index-util.h"
-#include "mail-lockdir.h"
-
-#include <time.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <sys/stat.h>
-
-#define DIRLOCK_FILE_PREFIX ".imap.dirlock"
-
-/* 0.1 .. 0.2msec */
-#define LOCK_RANDOM_USLEEP_TIME (100000 + (unsigned int)rand() % 100000)
-
-/* The dirlock should be used only while creating the index file. After the
-   header is written, the file itself should be locked and dirlock dropped
-   before index is built. So, this value shouldn't be very large, probably
-   even a few seconds would more than enough but we'll use a safe 10 seconds
-   by default. */
-#define MAX_LOCK_WAIT_SECONDS 10
-
-/* Non-local locks have a life time of 30 minutes, just to be sure that
-   small clock differences won't break things. */
-#define NFS_LOCK_TIMEOUT (60*30)
-
-static int mail_index_cleanup_dir_locks(const char *dir)
-{
-       const char *hostprefix, *path;
-       struct stat st;
-
-       hostprefix = t_strconcat(DIRLOCK_FILE_PREFIX ".",
-                                my_hostname, ".", NULL);
-
-       unlink_lockfiles(dir, hostprefix, DIRLOCK_FILE_PREFIX ".",
-                        time(NULL) - NFS_LOCK_TIMEOUT);
-
-       /* if hard link count has dropped to 1, we've unlocked the file */
-       path = t_strconcat(dir, "/" DIRLOCK_FILE_PREFIX, NULL);
-       if (stat(path, &st) == 0 && st.st_nlink == 1) {
-               /* only itself, safe to delete */
-               (void)unlink(path);
-               return TRUE;
-       }
-
-       return FALSE;
-}
-
-static int mail_index_unlock_dir(struct mail_index *index,
-                                const char *private_path, const char *lockpath)
-{
-       struct stat st, lockst;
-
-       if (stat(lockpath, &st) < 0)
-               return index_file_set_syscall_error(index, lockpath, "stat()");
-
-       if (st.st_nlink > 1) {
-               /* make sure we're really the one who's locked it */
-               if (stat(private_path, &lockst) < 0) {
-                       return index_file_set_syscall_error(index, private_path,
-                                                           "stat()");
-               }
-
-               if (st.st_dev != lockst.st_dev ||
-                   st.st_ino != lockst.st_ino) {
-                       index_set_error(index, "Unlocking file %s failed: "
-                                       "we're not the lock owner "
-                                       "(%lu,%lu vs %lu,%lu)", lockpath,
-                                       (unsigned long) st.st_dev,
-                                       (unsigned long) st.st_ino,
-                                       (unsigned long) lockst.st_dev,
-                                       (unsigned long) lockst.st_ino);
-                       return FALSE;
-               }
-       }
-
-       /* first unlink the actual lock file */
-       if (unlink(lockpath) < 0) {
-               index_file_set_syscall_error(index, lockpath, "unlink()");
-               return FALSE;
-       }
-
-       if (unlink(private_path) < 0) {
-               /* non-fatal */
-               index_file_set_syscall_error(index, private_path, "unlink()");
-       }
-       return TRUE;
-}
-
-int mail_index_lock_dir(struct mail_index *index,
-                       enum mail_lock_type lock_type)
-{
-       struct stat st;
-       const char *private_path, *lockpath;
-       int fd, orig_errno, first;
-       time_t max_wait_time;
-
-       i_assert(lock_type == MAIL_LOCK_EXCLUSIVE ||
-                lock_type == MAIL_LOCK_UNLOCK);
-
-       hostpid_init();
-
-       /* use .dirlock.host.pid as our lock indicator file and
-          .dirlock as the real lock */
-       private_path = t_strconcat(index->dir, "/" DIRLOCK_FILE_PREFIX ".",
-                                  my_hostname, ".", my_pid, NULL);
-       lockpath = t_strconcat(index->dir, "/" DIRLOCK_FILE_PREFIX, NULL);
-
-       if (lock_type == MAIL_LOCK_UNLOCK)
-               return mail_index_unlock_dir(index, private_path, lockpath);
-
-       (void)unlink(private_path);
-       fd = open(private_path, O_RDWR | O_CREAT | O_EXCL, 0660);
-       if (fd == -1) {
-               if (errno == ENOSPC)
-                       index->nodiskspace = TRUE;
-               index_file_set_syscall_error(index, private_path, "open()");
-               return FALSE;
-       }
-
-       /* try to link the file into lock file. */
-       first = TRUE; max_wait_time = time(NULL) + MAX_LOCK_WAIT_SECONDS;
-       while (link(private_path, lockpath) < 0) {
-               if (errno == ENOSPC)
-                       index->nodiskspace = TRUE;
-
-               if (errno != EEXIST) {
-                       orig_errno = errno;
-
-                       /* NFS may die and link() fail even if it really
-                          was created */
-                       if (stat(private_path, &st) == 0 && st.st_nlink == 2)
-                               break;
-
-                       errno = orig_errno;
-                       index_set_error(index, "link(%s, %s) lock failed: %m",
-                                       private_path, lockpath);
-                       return FALSE;
-               }
-
-               if (first) {
-                       /* cleanup lock files once */
-                       first = FALSE;
-                       if (mail_index_cleanup_dir_locks(index->dir))
-                               continue; /* lock was deleted, try again */
-               }
-
-               if (time(NULL) > max_wait_time) {
-                       index_set_error(index,
-                               "Timeout waiting for lock in directory %s",
-                               index->dir);
-                       return FALSE;
-               }
-
-               usleep(LOCK_RANDOM_USLEEP_TIME);
-       }
-
-       return TRUE;
-}
diff --git a/src/lib-index/mail-lockdir.h b/src/lib-index/mail-lockdir.h
deleted file mode 100644 (file)
index 0121997..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-#ifndef __MAIL_LOCKDIR_H
-#define __MAIL_LOCKDIR_H
-
-/* Exclusively lock whole directory where index is located. */
-int mail_index_lock_dir(struct mail_index *index,
-                       enum mail_lock_type lock_type);
-
-#endif
index a3dce486393d568ded0239308cfbddc4bb0b2702..2347a5cf70b76f36c48f36bc85a1fb2e8adbd1ee 100644 (file)
@@ -72,6 +72,11 @@ static int modifylog_set_syscall_error(struct modify_log_file *file,
 {
        i_assert(function != NULL);
 
+       if (errno == ENOSPC) {
+               file->log->index->nodiskspace = TRUE;
+               return FALSE;
+       }
+
        index_set_error(file->log->index,
                        "%s failed with modify log file %s: %m",
                        function, file->filepath);
@@ -318,25 +323,15 @@ static void mail_modifylog_init_header(struct mail_modify_log *log,
 
 static int mail_modifylog_init_fd(struct modify_log_file *file, int fd)
 {
-       struct mail_index *index = file->log->index;
         struct modify_log_header hdr;
 
         mail_modifylog_init_header(file->log, &hdr);
-       if (write_full(fd, &hdr, sizeof(hdr)) < 0) {
-               if (errno == ENOSPC)
-                       index->nodiskspace = TRUE;
-
-               modifylog_set_syscall_error(file, "write_full()");
-               return FALSE;
-       }
 
-       if (file_set_size(fd, MODIFY_LOG_INITIAL_SIZE) < 0) {
-               if (errno == ENOSPC)
-                       index->nodiskspace = TRUE;
+       if (write_full(fd, &hdr, sizeof(hdr)) < 0)
+               return modifylog_set_syscall_error(file, "write_full()");
 
-               modifylog_set_syscall_error(file, "file_set_size()");
-               return FALSE;
-       }
+       if (file_set_size(fd, MODIFY_LOG_INITIAL_SIZE) < 0)
+               return modifylog_set_syscall_error(file, "file_set_size()");
 
        return TRUE;
 }
@@ -372,14 +367,11 @@ static int modifylog_reuse_or_create_file(struct modify_log_file *file)
        struct mail_index *index = file->log->index;
        int fd, ret;
 
-       if (index->nodiskspace)
+       if (INDEX_IS_IN_MEMORY(index))
                return -1;
 
        fd = open(file->filepath, O_RDWR | O_CREAT, 0660);
        if (fd == -1) {
-               if (errno == ENOSPC)
-                       index->nodiskspace = TRUE;
-
                modifylog_set_syscall_error(file, "open()");
                return -1;
        }
@@ -532,7 +524,8 @@ static void modifylog_create_anon(struct modify_log_file *file)
        file->synced_position = file->mmap_used_length;
 
        file->anon_mmap = TRUE;
-       file->filepath = i_strdup("(in-memory modify log)");
+       file->filepath = i_strdup_printf("(in-memory modify log for %s)",
+                                        file->log->index->mailbox_path);
 }
 
 int mail_modifylog_create(struct mail_index *index)
@@ -544,7 +537,7 @@ int mail_modifylog_create(struct mail_index *index)
 
        log = mail_modifylog_new(index);
 
-       if (index->nodiskspace)
+       if (INDEX_IS_IN_MEMORY(index))
                modifylog_create_anon(&log->file1);
        else {
                ret = modifylog_reuse_or_create_file(&log->file1);
@@ -687,11 +680,8 @@ static int mail_modifylog_grow(struct modify_log_file *file)
                return TRUE;
        }
 
-       if (file_set_size(file->fd, (off_t)new_fsize) < 0) {
-               if (errno == ENOSPC)
-                       file->log->index->nodiskspace = TRUE;
+       if (file_set_size(file->fd, (off_t)new_fsize) < 0)
                return modifylog_set_syscall_error(file, "file_set_size()");
-       }
 
        if (!mmap_update(file, TRUE))
                return FALSE;
index 5a0b303782699e3394757f44e83ab7fe18235ddf..f0985557e65203de385fde5959e471daf873de85 100644 (file)
@@ -19,6 +19,11 @@ static int tree_set_syscall_error(struct mail_tree *tree, const char *function)
 {
        i_assert(function != NULL);
 
+       if (errno == ENOSPC) {
+               tree->index->nodiskspace = TRUE;
+               return FALSE;
+       }
+
        index_set_error(tree->index, "%s failed with binary tree file %s: %m",
                        function, tree->filepath);
        return FALSE;
@@ -153,9 +158,6 @@ static struct mail_tree *mail_tree_open(struct mail_index *index)
        path = t_strconcat(index->filepath, ".tree", NULL);
        fd = open(path, O_RDWR | O_CREAT, 0660);
        if (fd == -1) {
-               if (errno == ENOSPC)
-                       index->nodiskspace = TRUE;
-
                index_file_set_syscall_error(index, path, "open()");
                return NULL;
        }
@@ -177,7 +179,8 @@ static struct mail_tree *mail_tree_create_anon(struct mail_index *index)
        tree->anon_mmap = TRUE;
        tree->fd = -1;
        tree->index = index;
-       tree->filepath = i_strdup("(in-memory tree)");
+       tree->filepath = i_strdup_printf("(in-memory tree index for %s)",
+                                        index->mailbox_path);
 
        index->tree = tree;
        return tree;
@@ -189,7 +192,7 @@ int mail_tree_create(struct mail_index *index)
 
        i_assert(index->lock_type == MAIL_LOCK_EXCLUSIVE);
 
-       tree = !index->nodiskspace ? mail_tree_open(index) :
+       tree = !INDEX_IS_IN_MEMORY(index) ? mail_tree_open(index) :
                mail_tree_create_anon(index);
        if (tree == NULL)
                return FALSE;
@@ -306,19 +309,11 @@ static int mail_tree_init(struct mail_tree *tree)
        if (lseek(tree->fd, 0, SEEK_SET) < 0)
                return tree_set_syscall_error(tree, "lseek()");
 
-       if (write_full(tree->fd, &hdr, sizeof(hdr)) < 0) {
-               if (errno == ENOSPC)
-                       tree->index->nodiskspace = TRUE;
-
+       if (write_full(tree->fd, &hdr, sizeof(hdr)) < 0)
                return tree_set_syscall_error(tree, "write_full()");
-       }
-
-       if (file_set_size(tree->fd, MAIL_TREE_MIN_SIZE) < 0) {
-               if (errno == ENOSPC)
-                       tree->index->nodiskspace = TRUE;
 
+       if (file_set_size(tree->fd, MAIL_TREE_MIN_SIZE) < 0)
                return tree_set_syscall_error(tree, "file_set_size()");
-       }
 
        return TRUE;
 }
@@ -398,11 +393,8 @@ int _mail_tree_grow(struct mail_tree *tree)
                return mmap_verify(tree);
        }
 
-       if (file_set_size(tree->fd, (off_t)new_fsize) < 0) {
-               if (errno == ENOSPC)
-                       tree->index->nodiskspace = TRUE;
+       if (file_set_size(tree->fd, (off_t)new_fsize) < 0)
                return tree_set_syscall_error(tree, "file_set_size()");
-       }
 
        /* file size changed, let others know about it too by changing
           sync_id in header. */
index f15ee875be8ebd658a4570e8a245d006b11791ac..7ca058872c8bded0b5e87ff66829a8ff6d14f9d9 100644 (file)
 extern struct mail_index maildir_index;
 
 static int maildir_index_open(struct mail_index *index,
-                             int update_recent, int fast)
+                             enum mail_index_open_flags flags)
 {
        maildir_clean_tmp(t_strconcat(index->mailbox_path, "/tmp", NULL));
-       return mail_index_open(index, update_recent, fast);
+       return mail_index_open(index, flags);
 }
 
 enum mail_flags maildir_filename_get_flags(const char *fname,
@@ -145,7 +145,6 @@ struct mail_index *maildir_index_alloc(const char *dir, const char *maildir)
 {
        struct mail_index *index;
 
-       i_assert(dir != NULL);
        i_assert(maildir != NULL);
 
        index = i_new(struct mail_index, 1);
@@ -244,7 +243,6 @@ static int maildir_index_update_flags(struct mail_index *index,
 
 struct mail_index maildir_index = {
        maildir_index_open,
-       mail_index_open_or_create,
        maildir_index_free,
        mail_index_set_lock,
        mail_index_try_lock,
index aedbcbd5297593d1e505146802057ad1e3086e27..848a713b0285b3e02a109ce19866c3b4d245ff60 100644 (file)
@@ -730,7 +730,7 @@ struct mail_index *mbox_index_alloc(const char *dir, const char *mbox_path)
 {
        struct mail_index *index;
 
-       i_assert(dir != NULL);
+       i_assert(mbox_path != NULL);
 
        index = i_new(struct mail_index, 1);
        memcpy(index, &mbox_index, sizeof(struct mail_index));
@@ -801,7 +801,6 @@ static int mbox_index_update_flags(struct mail_index *index,
 
 struct mail_index mbox_index = {
        mail_index_open,
-       mail_index_open_or_create,
        mbox_index_free,
        mbox_index_set_lock,
        mbox_index_try_lock,
index 7b5250f08ec57e80db5ed07b3aba3cdddea92e07..5b96f9a4b255c5fe85b60d5966cd2345a03e96bd 100644 (file)
@@ -226,6 +226,7 @@ index_storage_init(struct mail_storage *storage, struct mailbox *box,
                   int readonly, int fast)
 {
        struct index_mailbox *ibox;
+       enum mail_index_open_flags flags;
 
        i_assert(name != NULL);
 
@@ -236,7 +237,6 @@ index_storage_init(struct mail_storage *storage, struct mailbox *box,
                ibox->box.storage = storage;
                ibox->box.name = i_strdup(name);
                ibox->box.readonly = readonly;
-               ibox->box.allow_custom_flags = TRUE;
 
                ibox->index = index;
 
@@ -249,13 +249,29 @@ index_storage_init(struct mail_storage *storage, struct mailbox *box,
                                get_default_cache_fields();
                        index->never_cache_fields =
                                get_never_cache_fields();
-                       if (!index->open_or_create(index, !readonly, fast))
+
+                       flags = MAIL_INDEX_OPEN_FLAG_CREATE;
+                       if (fast)
+                               flags |= MAIL_INDEX_OPEN_FLAG_FAST;
+                       if (!readonly)
+                               flags |= MAIL_INDEX_OPEN_FLAG_UPDATE_RECENT;
+
+                       if (!index->open(index, flags))
                                break;
+
+                       if (INDEX_IS_IN_MEMORY(index) &&
+                           storage->index_dir != NULL) {
+                               storage->callbacks->notify_no(&ibox->box,
+                                       "Couldn't use index files",
+                                       storage->callback_context);
+                       }
                }
 
                if (!ibox->index->set_lock(ibox->index, MAIL_LOCK_SHARED))
                        break;
 
+               ibox->box.allow_custom_flags =
+                       ibox->index->allow_new_custom_flags;
                ibox->synced_messages_count =
                        mail_index_get_header(index)->messages_count;
 
index 02e6085d3d651a5af7ba6836d54ceaccc8f52b59..8e3ff46f932ab3c1805ba13caabc627b758a94dd 100644 (file)
@@ -65,6 +65,8 @@ static struct mail_storage *maildir_create(const char *data, const char *user)
 
        if (index_dir == NULL)
                index_dir = root_dir;
+       else if (strcmp(index_dir, "MEMORY") == 0)
+               index_dir = NULL;
 
        storage = i_new(struct mail_storage, 1);
        memcpy(storage, &maildir_storage, sizeof(struct mail_storage));
@@ -90,6 +92,8 @@ static int maildir_autodetect(const char *data)
 {
        struct stat st;
 
+       data = t_strcut(data, ':');
+
        return stat(t_strconcat(data, "/cur", NULL), &st) == 0 &&
                S_ISDIR(st.st_mode);
 }
@@ -134,6 +138,9 @@ const char *maildir_get_path(struct mail_storage *storage, const char *name)
 static const char *maildir_get_index_path(struct mail_storage *storage,
                                          const char *name)
 {
+       if (storage->index_dir == NULL)
+               return NULL;
+
        if (full_filesystem_access && (*name == '/' || *name == '~'))
                return maildir_get_absolute_path(name);
 
@@ -209,6 +216,7 @@ maildir_open(struct mail_storage *storage, const char *name,
        index = index_storage_lookup_ref(index_dir);
        if (index == NULL) {
                index = maildir_index_alloc(index_dir, path);
+               index->custom_flags_dir = i_strdup(path);
                index_storage_add(index);
        }
 
index 273c5330aafeff867b9dc719495c5d9a43a4559e..e3e7348004a5396201134603567cffb3550fcbea 100644 (file)
@@ -54,6 +54,8 @@ static int mbox_autodetect(const char *data)
        const char *path;
        struct stat st;
 
+       data = t_strcut(data, ':');
+
        /* Is it INBOX file? */
        if (*data != '\0' && stat(data, &st) == 0 && !S_ISDIR(st.st_mode) &&
            access(data, R_OK|W_OK) == 0)
@@ -191,8 +193,11 @@ static struct mail_storage *mbox_create(const char *data, const char *user)
 
        if (inbox_file == NULL)
                inbox_file = get_inbox_file(root_dir, !autodetect);
+
        if (index_dir == NULL)
                index_dir = root_dir;
+       else if (strcmp(index_dir, "MEMORY") == 0)
+               index_dir = NULL;
 
        storage = i_new(struct mail_storage, 1);
        memcpy(storage, &mbox_storage, sizeof(struct mail_storage));
@@ -254,6 +259,9 @@ static const char *mbox_get_index_dir(struct mail_storage *storage,
 {
        const char *p;
 
+       if (storage->index_dir == NULL)
+               return NULL;
+
        if (full_filesystem_access && (*name == '/' || *name == '~')) {
                name = home_expand(name);
                p = strrchr(name, '/');
@@ -277,6 +285,9 @@ static int create_mbox_index_dirs(struct mail_storage *storage,
        const char *index_dir, *imap_dir;
 
        index_dir = mbox_get_index_dir(storage, name);
+       if (index_dir == NULL)
+               return TRUE;
+
        imap_dir = t_strdup_until(index_dir, strstr(index_dir, ".imap/") + 5);
 
        if (mkdir(imap_dir, CREATE_MODE) == -1 && errno != EEXIST)
@@ -333,6 +344,7 @@ static struct mailbox *mbox_open(struct mail_storage *storage, const char *name,
        index = index_storage_lookup_ref(index_dir);
        if (index == NULL) {
                index = mbox_index_alloc(index_dir, path);
+               index->custom_flags_dir = i_strdup(index_dir);
                index_storage_add(index);
        }
 
@@ -511,7 +523,8 @@ static int mbox_delete_mailbox(struct mail_storage *storage, const char *name)
 
        /* next delete the index directory */
        index_dir = mbox_get_index_dir(storage, name);
-       if (unlink_directory(index_dir, TRUE) < 0 && errno != ENOENT) {
+       if (index_dir != NULL &&
+           unlink_directory(index_dir, TRUE) < 0 && errno != ENOENT) {
                mail_storage_set_critical(storage, "unlink_directory(%s) "
                                          "failed: %m", index_dir);
                return FALSE;
@@ -566,7 +579,8 @@ static int mbox_rename_mailbox(struct mail_storage *storage,
        /* we need to rename the index directory as well */
        old_indexdir = mbox_get_index_dir(storage, oldname);
        new_indexdir = mbox_get_index_dir(storage, newname);
-       (void)rename(old_indexdir, new_indexdir);
+       if (old_indexdir != NULL)
+               (void)rename(old_indexdir, new_indexdir);
 
        return TRUE;
 }
index 3e43c10721a3b74f0e40ddb14bfc62811327bfca..703b3860d53208c1ccad7a361d94e880e68efe7d 100644 (file)
@@ -175,8 +175,6 @@ int create_mail_process(int socket, struct ip_addr *ip,
                env_put("MAILDIR_COPY_WITH_HARDLINKS=1");
        if (set->maildir_check_content_changes)
                env_put("MAILDIR_CHECK_CONTENT_CHANGES=1");
-       if (set->overwrite_incompatible_index)
-               env_put("OVERWRITE_INCOMPATIBLE_INDEX=1");
        if (set->mail_full_filesystem_access)
                env_put("FULL_FILESYSTEM_ACCESS=1");
        (void)umask(set->umask);
index 715614dacebc2c4a1cd44a7ffbcee67c30b552e1..cfdcf09f12ea6ef8382795f455951f67c262382d 100644 (file)
@@ -67,7 +67,6 @@ static struct setting_def setting_defs[] = {
        DEF(SET_BOOL, mbox_read_dotlock),
        DEF(SET_INT, mbox_lock_timeout),
        DEF(SET_INT, mbox_dotlock_change_timeout),
-       DEF(SET_BOOL, overwrite_incompatible_index),
        DEF(SET_INT, umask),
        DEF(SET_BOOL, mail_drop_priv_before_exec),
 
@@ -174,7 +173,6 @@ struct settings default_settings = {
        MEMBER(mbox_read_dotlock) FALSE,
        MEMBER(mbox_lock_timeout) 300,
        MEMBER(mbox_dotlock_change_timeout) 30,
-       MEMBER(overwrite_incompatible_index) FALSE,
        MEMBER(umask) 0077,
        MEMBER(mail_drop_priv_before_exec) FALSE,
 
index 2be8048e787cfd1b35a7acd26447c58d9043a39d..4edbc6176a3e3e7c9bde252f0d962f2c3998e7dd 100644 (file)
@@ -51,7 +51,6 @@ struct settings {
        int mbox_read_dotlock;
        unsigned int mbox_lock_timeout;
        unsigned int mbox_dotlock_change_timeout;
-       int overwrite_incompatible_index;
        unsigned int umask;
        int mail_drop_priv_before_exec;