Mercurial > dovecot > core-2.2
changeset 1343:e80c784252ea HEAD
Rewritten maildir syncing. Uses dovecot-uidlist file to store UIDs
permanently.
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Wed, 09 Apr 2003 23:10:01 +0300 |
parents | f1dc24e5bc0f |
children | 2dcd8cebe5e6 |
files | src/lib-index/mail-index-open.c src/lib-index/mail-index.h src/lib-index/maildir/Makefile.am src/lib-index/maildir/maildir-build.c src/lib-index/maildir/maildir-index.c src/lib-index/maildir/maildir-index.h src/lib-index/maildir/maildir-rebuild.c src/lib-index/maildir/maildir-sync.c src/lib-index/maildir/maildir-uidlist.c src/lib-index/maildir/maildir-uidlist.h src/lib-storage/index/maildir/maildir-save.c src/lib-storage/index/maildir/maildir-storage.h |
diffstat | 12 files changed, 917 insertions(+), 355 deletions(-) [+] |
line wrap: on
line diff
--- a/src/lib-index/mail-index-open.c Wed Apr 09 23:07:47 2003 +0300 +++ b/src/lib-index/mail-index-open.c Wed Apr 09 23:10:01 2003 +0300 @@ -64,6 +64,8 @@ static int index_open_and_fix(struct mail_index *index, enum mail_index_open_flags flags) { + int rebuilt; + /* open/create the index files */ if ((flags & _MAIL_INDEX_OPEN_FLAG_CREATING) == 0) { if (!mail_index_data_open(index)) { @@ -97,6 +99,9 @@ /* no inconsistency problems since we're still opening the index */ index->inconsistent = FALSE; + rebuilt = TRUE; + } else { + rebuilt = FALSE; } if ((flags & _MAIL_INDEX_OPEN_FLAG_CREATING) == 0) { @@ -122,11 +127,14 @@ return FALSE; } - /* 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; - index->inconsistent = FALSE; + if (!rebuilt) { + /* 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; + + index->inconsistent = FALSE; + } /* we never want to keep shared lock if syncing happens to set it. either exclusive or nothing (NOTE: drop it directly, not through
--- a/src/lib-index/mail-index.h Wed Apr 09 23:07:47 2003 +0300 +++ b/src/lib-index/mail-index.h Wed Apr 09 23:10:01 2003 +0300 @@ -393,6 +393,14 @@ dev_t mbox_dev; ino_t mbox_ino; + /* last maildir sync: */ + dev_t uidlist_dev; + ino_t uidlist_ino; + time_t uidlist_mtime; + off_t uidlist_size; + + int maildir_lock_fd; + int fd; /* opened index file */ char *error; /* last error message */ @@ -416,6 +424,7 @@ unsigned int anon_mmap:1; unsigned int opened:1; + unsigned int rebuilding:1; unsigned int mail_read_mmaped:1; unsigned int inconsistent:1; unsigned int nodiskspace:1; @@ -438,7 +447,8 @@ 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_. */
--- a/src/lib-index/maildir/Makefile.am Wed Apr 09 23:07:47 2003 +0300 +++ b/src/lib-index/maildir/Makefile.am Wed Apr 09 23:10:01 2003 +0300 @@ -13,6 +13,7 @@ maildir-open.c \ maildir-rebuild.c \ maildir-sync.c \ + maildir-uidlist.c \ maildir-update.c noinst_HEADERS = \
--- a/src/lib-index/maildir/maildir-build.c Wed Apr 09 23:07:47 2003 +0300 +++ b/src/lib-index/maildir/maildir-build.c Wed Apr 09 23:10:01 2003 +0300 @@ -1,6 +1,7 @@ /* Copyright (C) 2002 Timo Sirainen */ #include "lib.h" +#include "str.h" #include "maildir-index.h" #include "mail-index-data.h" #include "mail-index-util.h" @@ -103,64 +104,59 @@ return ret; } -int maildir_index_build_dir(struct mail_index *index, const char *source_dir, - const char *dest_dir) +int maildir_index_build_dir(struct mail_index *index, + const char *source_dir, const char *dest_dir, + DIR *dirp, struct dirent *d) { - DIR *dirp; const char *final_dir; - struct dirent *d; - struct stat st; - char sourcepath[PATH_MAX], destpath[PATH_MAX]; + string_t *sourcepath, *destpath; int failed; + i_assert(index->maildir_lock_fd != -1); i_assert(index->lock_type != MAIL_LOCK_SHARED); - i_assert(source_dir != NULL); - dirp = opendir(source_dir); - if (dirp == NULL) { - return index_file_set_syscall_error(index, source_dir, - "opendir()"); - } + sourcepath = t_str_new(PATH_MAX); + destpath = t_str_new(PATH_MAX); final_dir = dest_dir != NULL ? dest_dir : source_dir; failed = FALSE; - while (!failed && (d = readdir(dirp)) != NULL) { + for (; d != NULL && !failed; d = readdir(dirp)) { if (d->d_name[0] == '.') continue; if (dest_dir != NULL) { - /* move the file into dest_dir - abort everything if it - already exists, as that should never happen */ - if (str_path(sourcepath, sizeof(sourcepath), - source_dir, d->d_name) < 0) { - index_set_error(index, "Path too long: %s/%s", - source_dir, d->d_name); - failed = TRUE; - break; - } - if (str_path(destpath, sizeof(destpath), - dest_dir, d->d_name) < 0) { - index_set_error(index, "Path too long: %s/%s", - dest_dir, d->d_name); - failed = TRUE; - break; - } - if (stat(destpath, &st) == 0) { - index_set_error(index, "Can't move mail %s to " - "%s: file already exists", - sourcepath, destpath); - failed = TRUE; - break; - } + /* rename() has the problem that it might overwrite + some mails, but that happens only with a broken + client that has created non-unique base name. + + Alternative would be link() + unlink(), but that's + racy when multiple clients try to move the mail from + new/ to cur/: + + a) One of the clients uses slightly different + filename (eg. sets flags) + + b) Third client changes mail's flag between + client1's unlink() and client2's link() calls. - /* race condition here - ignore it as the chance of it - happening is pretty much zero */ + Checking first if file exists with stat() is pretty + useless as well. It requires that we also stat the + file in new/, to make sure that the dest file isn't + actually the same file which someone _just_ had + rename()d. */ + str_truncate(sourcepath, 0); + str_truncate(destpath, 0); - if (rename(sourcepath, destpath) < 0) { + str_printfa(sourcepath, "%s/%s", source_dir, d->d_name); + str_printfa(destpath, "%s/%s", dest_dir, d->d_name); + + if (rename(str_c(sourcepath), str_c(destpath)) < 0 && + errno != ENOENT) { index_set_error(index, "maildir build: " "rename(%s, %s) failed: %m", - sourcepath, destpath); + str_c(sourcepath), + str_c(destpath)); failed = TRUE; break; } @@ -172,7 +168,5 @@ t_pop(); } - if (closedir(dirp) < 0) - index_file_set_syscall_error(index, source_dir, "closedir()"); return !failed; }
--- a/src/lib-index/maildir/maildir-index.c Wed Apr 09 23:07:47 2003 +0300 +++ b/src/lib-index/maildir/maildir-index.c Wed Apr 09 23:10:01 2003 +0300 @@ -1,6 +1,8 @@ /* Copyright (C) 2002 Timo Sirainen */ #include "lib.h" +#include "ioloop.h" +#include "hostpid.h" #include "str.h" #include "maildir-index.h" #include "mail-index-data.h" @@ -8,6 +10,8 @@ #include <stdio.h> #include <sys/stat.h> +#include <sys/time.h> +#include <time.h> extern struct mail_index maildir_index; @@ -31,6 +35,53 @@ return fname; } +const char *maildir_generate_tmp_filename(const struct timeval *tv) +{ + static unsigned int create_count = 0; + + return t_strdup_printf("%s.P%sQ%uM%s.%s", + dec2str(tv->tv_sec), my_pid, create_count++, + dec2str(tv->tv_usec), my_hostname); +} + +int maildir_create_tmp(struct mail_index *index, const char *dir, + const char **fname) +{ + const char *path, *tmp_fname; + struct stat st; + struct timeval *tv, tv_now; + pool_t pool; + int fd; + + tv = &ioloop_timeval; + pool = pool_alloconly_create("maildir_tmp", 4096); + for (;;) { + p_clear(pool); + tmp_fname = maildir_generate_tmp_filename(tv); + + path = p_strconcat(pool, dir, "/", tmp_fname, NULL); + if (stat(path, &st) < 0 && errno == ENOENT) { + /* doesn't exist */ + fd = open(path, O_WRONLY | O_CREAT | O_EXCL, 0600); + if (fd != -1 || errno != EEXIST) + break; + } + + /* wait and try again - very unlikely */ + sleep(2); + tv = &tv_now; + if (gettimeofday(&tv_now, NULL) < 0) + i_fatal("gettimeofday(): %m"); + } + + *fname = t_strdup(path); + if (fd == -1) + index_file_set_syscall_error(index, path, "open()"); + + pool_unref(pool); + return fd; +} + enum mail_flags maildir_filename_get_flags(const char *fname, enum mail_flags default_flags) { @@ -163,6 +214,7 @@ index = i_new(struct mail_index, 1); memcpy(index, &maildir_index, sizeof(struct mail_index)); + index->maildir_lock_fd = -1; index->mailbox_path = i_strdup(maildir); mail_index_init(index, dir); return index;
--- a/src/lib-index/maildir/maildir-index.h Wed Apr 09 23:07:47 2003 +0300 +++ b/src/lib-index/maildir/maildir-index.h Wed Apr 09 23:10:01 2003 +0300 @@ -1,6 +1,7 @@ #ifndef __MAILDIR_INDEX_H #define __MAILDIR_INDEX_H +#include <dirent.h> #include "mail-index.h" /* ":2,DFRST" - leave the 2 extra for other clients' additions */ @@ -8,6 +9,11 @@ struct mail_index *maildir_index_alloc(const char *dir, const char *maildir); +/* Return new filename base to save into tmp/ */ +const char *maildir_generate_tmp_filename(const struct timeval *tv); +int maildir_create_tmp(struct mail_index *index, const char *dir, + const char **path); + const char *maildir_get_location(struct mail_index *index, struct mail_index_record *rec); enum mail_flags maildir_filename_get_flags(const char *fname, @@ -21,8 +27,9 @@ int maildir_index_append_file(struct mail_index *index, const char *dir, const char *fname); -int maildir_index_build_dir(struct mail_index *index, const char *source_dir, - const char *dest_dir); +int maildir_index_build_dir(struct mail_index *index, + const char *source_dir, const char *dest_dir, + DIR *dirp, struct dirent *d); struct istream *maildir_open_mail(struct mail_index *index, struct mail_index_record *rec,
--- a/src/lib-index/maildir/maildir-rebuild.c Wed Apr 09 23:07:47 2003 +0300 +++ b/src/lib-index/maildir/maildir-rebuild.c Wed Apr 09 23:10:01 2003 +0300 @@ -11,11 +11,6 @@ int maildir_index_rebuild(struct mail_index *index) { - struct stat st; - const char *cur_dir, *new_dir; - - i_assert(index->lock_type != MAIL_LOCK_SHARED); - if (!mail_index_set_lock(index, MAIL_LOCK_EXCLUSIVE)) return FALSE; @@ -30,6 +25,7 @@ changed */ index->indexid = index->header->indexid; index->inconsistent = TRUE; + index->rebuilding = TRUE; if (msync(index->mmap_base, sizeof(struct mail_index_header), MS_SYNC) < 0) @@ -39,23 +35,12 @@ if (!mail_index_data_reset(index->data)) return FALSE; - /* rebuild cur/ directory */ - cur_dir = t_strconcat(index->mailbox_path, "/cur", NULL); - if (!maildir_index_build_dir(index, cur_dir, NULL)) + /* read the mails by syncing */ + if (!index->sync_and_lock(index, MAIL_LOCK_UNLOCK, NULL)) return FALSE; - /* also see if there's new mail */ - new_dir = t_strconcat(index->mailbox_path, "/new", NULL); - if (!maildir_index_build_dir(index, new_dir, cur_dir)) - return FALSE; - - /* update sync stamp */ - if (stat(cur_dir, &st) < 0) - return index_file_set_syscall_error(index, cur_dir, "stat()"); - - index->file_sync_stamp = st.st_mtime; - /* rebuild is complete - remove the flag */ index->header->flags &= ~(MAIL_INDEX_FLAG_REBUILD|MAIL_INDEX_FLAG_FSCK); + index->rebuilding = FALSE; return TRUE; }
--- a/src/lib-index/maildir/maildir-sync.c Wed Apr 09 23:07:47 2003 +0300 +++ b/src/lib-index/maildir/maildir-sync.c Wed Apr 09 23:10:01 2003 +0300 @@ -1,9 +1,11 @@ -/* Copyright (C) 2002 Timo Sirainen */ +/* Copyright (C) 2002-2003 Timo Sirainen */ #include "lib.h" -#include "ioloop.h" +#include "buffer.h" #include "hash.h" +#include "ioloop.h" #include "maildir-index.h" +#include "maildir-uidlist.h" #include "mail-index-data.h" #include "mail-index-util.h" @@ -14,185 +16,294 @@ #include <utime.h> #include <sys/stat.h> -static int maildir_index_sync_file(struct mail_index *index, +enum maildir_file_action { + MAILDIR_FILE_ACTION_EXPUNGE, + MAILDIR_FILE_ACTION_UPDATE_FLAGS, + MAILDIR_FILE_ACTION_UPDATE_CONTENT, + MAILDIR_FILE_ACTION_NEW, + MAILDIR_FILE_ACTION_NONE +}; + +struct maildir_hash_context { + struct mail_index *index; + struct mail_index_record *new_mail; + + int failed; +}; + +struct maildir_hash_rec { + struct mail_index_record *rec; + enum maildir_file_action action; +}; + +static int maildir_update_filename(struct mail_index *index, struct mail_index_record *rec, - unsigned int seq, const char *fname, - const char *path, int fname_changed) + const char *new_fname) { struct mail_index_update *update; - enum mail_flags flags; - int failed; - i_assert(fname != NULL); - i_assert(path != NULL); - - if (!index->set_lock(index, MAIL_LOCK_EXCLUSIVE)) - return FALSE; - - failed = FALSE; update = index->update_begin(index, rec); - - if (fname_changed) - index->update_field(update, DATA_FIELD_LOCATION, fname, 0); - - if (!index->update_end(update)) - failed = TRUE; - - /* update flags after filename has been updated, so it can be - compared correctly */ - flags = maildir_filename_get_flags(fname, rec->msg_flags); - if (!failed && flags != rec->msg_flags) { - if (!index->update_flags(index, rec, seq, flags, TRUE)) - failed = TRUE; - } - - return !failed; + index->update_field(update, DATA_FIELD_LOCATION, new_fname, 0); + return index->update_end(update); } -static int maildir_index_sync_files(struct mail_index *index, const char *dir, - struct hash_table *files, - int check_content_changes) +static int maildir_update_flags(struct mail_index *index, + struct mail_index_record *rec, + unsigned int seq, const char *new_fname) { - struct mail_index_record *rec; - struct mail_index_data_record_header *data_hdr; - struct stat st; - const char *fname, *base_fname, *value; - char path[PATH_MAX]; - unsigned int seq; - int fname_changed; - - i_assert(dir != NULL); - - rec = index->lookup(index, 1); - for (seq = 1; rec != NULL; rec = index->next(index, rec)) { - fname = maildir_get_location(index, rec); - if (fname == NULL) - return FALSE; - - t_push(); - - /* get the filename without the ":flags" part */ - base_fname = t_strcut(fname, ':'); - - value = hash_lookup(files, base_fname); - if (value != NULL) - hash_remove(files, base_fname); - - t_pop(); - - if (value == NULL) { - /* mail is expunged */ - if (!index->set_lock(index, MAIL_LOCK_EXCLUSIVE)) - return FALSE; - - if (!index->expunge(index, rec, seq, TRUE)) - return FALSE; - continue; - } + enum mail_flags flags; - /* file still exists */ - if (str_path(path, sizeof(path), dir, value) < 0) { - index_set_error(index, "Path too long: %s/%s", - dir, value); + flags = maildir_filename_get_flags(new_fname, rec->msg_flags); + if (flags != rec->msg_flags) { + if (!index->update_flags(index, rec, seq, flags, TRUE)) return FALSE; - } - - if (check_content_changes) { - if (stat(path, &st) < 0) { - index_file_set_syscall_error(index, path, - "stat()"); - return FALSE; - } - - data_hdr = mail_index_data_lookup_header(index->data, - rec); - if (data_hdr != NULL && - (st.st_mtime != data_hdr->internal_date || - (uoff_t)st.st_size != - data_hdr->body_size + data_hdr->header_size)) { - /* file changed. IMAP doesn't allow that, so - we have to treat it as a new message. */ - if (!index->set_lock(index, - MAIL_LOCK_EXCLUSIVE)) - return FALSE; - - if (!index->expunge(index, rec, seq, TRUE)) - return FALSE; - continue; - } - } - - /* changed - update */ - fname_changed = strcmp(value, fname) != 0; - if (fname_changed) { - if (!maildir_index_sync_file(index, rec, seq, value, - path, fname_changed)) - return FALSE; - } - - seq++; - } - - if (seq-1 != index->header->messages_count) { - index_set_corrupted(index, "Wrong messages_count in header " - "(%u != %u)", seq-1, - index->header->messages_count); - return FALSE; } return TRUE; } -struct hash_append_context { - struct mail_index *index; - const char *dir; - int failed; -}; +static int is_file_content_changed(struct mail_index *index, + struct mail_index_record *rec, + const char *dir, const char *fname) +{ +#define DATA_HDR_SIZE (DATA_HDR_HEADER_SIZE | DATA_HDR_BODY_SIZE) + struct mail_index_data_record_header *data_hdr; + struct stat st; + const char *path; -static void maildir_index_hash_append_file(void *key __attr_unused__, - void *value, void *context) -{ - struct hash_append_context *ctx = context; + if ((rec->data_fields & DATA_HDR_INTERNAL_DATE) == 0 && + (rec->data_fields & DATA_HDR_SIZE) != DATA_HDR_SIZE) { + /* nothing in cache, we can't know if it's changed */ + return FALSE; + } t_push(); - if (!maildir_index_append_file(ctx->index, ctx->dir, value)) { - ctx->failed = TRUE; - hash_foreach_stop(); + path = t_strdup_printf("%s/%s", dir, fname); + + if (stat(path, &st) < 0) { + if (errno != ENOENT) + index_file_set_syscall_error(index, path, "stat()"); + t_pop(); + return FALSE; } t_pop(); + + data_hdr = mail_index_data_lookup_header(index->data, rec); + if (data_hdr == NULL) + return FALSE; + + if ((rec->data_fields & DATA_HDR_INTERNAL_DATE) != 0 && + st.st_mtime != data_hdr->internal_date) + return TRUE; + + if ((rec->data_fields & DATA_HDR_SIZE) == DATA_HDR_SIZE && + (uoff_t)st.st_size != data_hdr->body_size + data_hdr->header_size) + return TRUE; + + return FALSE; +} + +/* a char* hash function from ASU -- from glib */ +static unsigned int maildir_hash(const void *p) +{ + const unsigned char *s = p; + unsigned int g, h = 0; + + while (*s != ':' && *s != '\0') { + h = (h << 4) + *s; + if ((g = h & 0xf0000000UL)) { + h = h ^ (g >> 24); + h = h ^ g; + } + s++; + } + + return h; +} + +static int maildir_cmp(const void *p1, const void *p2) +{ + const char *s1 = p1, *s2 = p2; + + while (*s1 == *s2 && *s1 != ':' && *s1 != '\0') { + s1++; s2++; + } + if ((*s1 == '\0' || *s1 == ':') && + (*s2 == '\0' || *s2 == '\0')) + return 0; + return *s1 - *s2; +} + +static void uidlist_hash_get_filenames(void *key, void *value, void *context) +{ + buffer_t *buf = context; + struct maildir_hash_rec *hash_rec = value; + + if (hash_rec->action == MAILDIR_FILE_ACTION_NEW) + buffer_append(buf, (const void *) &key, sizeof(key)); } -static int maildir_index_append_files(struct mail_index *index, const char *dir, - struct hash_table *files) +static int maildir_sync_uidlist(struct mail_index *index, const char *dir, + struct maildir_uidlist *uidlist, + struct hash_table *files, pool_t pool, + unsigned int new_count) { - struct hash_append_context ctx; + struct mail_index_record *rec; + struct maildir_hash_rec *hash_rec; + struct maildir_uidlist_rec uid_rec; + const char *fname, **new_files; + void *orig_key, *orig_value; + unsigned int seq, last_uid, i; + buffer_t *buf; + + seq = 0; + rec = index->lookup(index, 1); + + if (uidlist == NULL) + memset(&uid_rec, 0, sizeof(uid_rec)); + else { + if (maildir_uidlist_next(uidlist, &uid_rec) < 0) + return FALSE; + } + + while (rec != NULL) { + seq++; + + /* skip over the expunged records in uidlist */ + while (uid_rec.uid != 0 && uid_rec.uid < rec->uid) { + uidlist->rewrite = TRUE; + if (!maildir_uidlist_next(uidlist, &uid_rec)) + return FALSE; + } + + fname = maildir_get_location(index, rec); + if (fname == NULL) { + hash_destroy(files); + return FALSE; + } + + hash_rec = hash_lookup(files, fname); + if (hash_rec == NULL) { + index_set_corrupted(index, "Unexpectedly lost file " + "%s from hash", fname); + return FALSE; + } + + if (uid_rec.uid != 0 && + maildir_cmp(fname, uid_rec.filename) != 0) { + index_set_corrupted(index, "Filename mismatch for UID " + "%u: %s vs %s", rec->uid, fname, + uid_rec.filename); + return FALSE; + } - ctx.failed = FALSE; - ctx.index = index; - ctx.dir = dir; - hash_foreach(files, maildir_index_hash_append_file, &ctx); + switch (hash_rec->action) { + case MAILDIR_FILE_ACTION_EXPUNGE: + if (!index->expunge(index, rec, seq, TRUE)) + return FALSE; + seq--; + break; + case MAILDIR_FILE_ACTION_UPDATE_FLAGS: + if (!maildir_update_flags(index, rec, seq, fname)) + return FALSE; + break; + case MAILDIR_FILE_ACTION_UPDATE_CONTENT: + if (!index->expunge(index, rec, seq, TRUE)) + return FALSE; + seq--; + hash_rec->action = MAILDIR_FILE_ACTION_NEW; + new_count++; + break; + case MAILDIR_FILE_ACTION_NONE: + break; + default: + i_unreached(); + } + + if (uid_rec.uid != 0) { + if (maildir_uidlist_next(uidlist, &uid_rec) < 0) + return FALSE; + } + rec = index->next(index, rec); + } + + if (seq != index->header->messages_count) { + index_set_corrupted(index, "Wrong messages_count in header " + "(%u != %u)", seq, + index->header->messages_count); + return FALSE; + } - return !ctx.failed; + /* if there's mails with UIDs in uidlist, write them */ + last_uid = 0; + while (uid_rec.uid != 0) { + if (!hash_lookup_full(files, uid_rec.filename, + &orig_key, &orig_value)) { + /* expunged */ + if (uidlist != NULL) + uidlist->rewrite = TRUE; + } else { + hash_rec = orig_value; + i_assert(hash_rec->action == MAILDIR_FILE_ACTION_NEW); + + /* make sure we set the same UID for it. */ + i_assert(index->header->next_uid <= uid_rec.uid); + index->header->next_uid = uid_rec.uid; + + hash_rec->action = MAILDIR_FILE_ACTION_NONE; + new_count--; + + if (!maildir_index_append_file(index, dir, orig_key)) + return FALSE; + } + + if (maildir_uidlist_next(uidlist, &uid_rec) < 0) + return FALSE; + } + + if (new_count == 0) { + /* all done */ + return TRUE; + } + + if (uidlist != NULL) + uidlist->rewrite = TRUE; + + /* then there's the completely new mails. sort them by the filename + so we should get them to same order as they were created. */ + buf = buffer_create_static_hard(pool, new_count * sizeof(const char *)); + hash_foreach(files, uidlist_hash_get_filenames, buf); + i_assert(buffer_get_used_size(buf) / sizeof(const char *) <= new_count); + + new_files = buffer_get_modifyable_data(buf, NULL); + qsort(new_files, new_count, sizeof(const char *), + (int (*)(const void *, const void *)) strcmp); + + /* and finally write */ + for (i = 0; i < new_count; i++) { + if (!maildir_index_append_file(index, dir, new_files[i])) + return FALSE; + } + + return TRUE; } -static int maildir_index_sync_dir(struct mail_index *index, const char *dir) +static int maildir_index_sync_dir(struct mail_index *index, const char *dir, + struct maildir_uidlist *uidlist) { pool_t pool; struct hash_table *files; + struct mail_index_record *rec; + struct maildir_hash_rec *hash_rec; DIR *dirp; struct dirent *d; - char *key, *value, *p; - unsigned int count; + const char *fname; + void *orig_key, *orig_value; + unsigned int new_count; int failed, check_content_changes; i_assert(dir != NULL); - - /* get exclusive lock always, this way the index file's timestamp - is updated even if there's no changes, which is useful to make - sure the cur/ directory isn't scanned all the time when it's - timestamp has changed but hasn't had any other changes. */ - if (!index->set_lock(index, MAIL_LOCK_EXCLUSIVE)) - return FALSE; + i_assert(index->lock_type == MAIL_LOCK_EXCLUSIVE); if (index->header->messages_count >= INT_MAX/32) { index_set_corrupted(index, "Header says %u messages", @@ -200,131 +311,260 @@ return FALSE; } - /* we need to find out the new and the deleted files. do this by - first building a hash of what files really exist, then go through - the index and after updated/removed the index, remove the file - from hash, so finally the hash should contain only the new - files which will be added then. */ + /* read current messages in index into hash */ + pool = pool_alloconly_create("maildir sync", 16384); + files = hash_create(default_pool, pool, index->header->messages_count*2, + maildir_hash, maildir_cmp); + + rec = index->lookup(index, 1); + while (rec != NULL) { + fname = maildir_get_location(index, rec); + if (fname == NULL) { + hash_destroy(files); + return FALSE; + } + hash_rec = p_new(pool, struct maildir_hash_rec, 1); + hash_rec->rec = rec; + hash_rec->action = MAILDIR_FILE_ACTION_EXPUNGE; + hash_insert(files, (void *) fname, hash_rec); + + rec = index->next(index, rec); + } + + /* Do we want to check changes in file contents? This slows down + things as we need to do extra stat() for all files. */ + check_content_changes = getenv("MAILDIR_CHECK_CONTENT_CHANGES") != NULL; + dirp = opendir(dir); if (dirp == NULL) return index_file_set_syscall_error(index, dir, "opendir()"); - count = index->header->messages_count + 16; - pool = pool_alloconly_create("Maildir sync", count*30); - files = hash_create(default_pool, pool, index->header->messages_count*2, - str_hash, (hash_cmp_callback_t *)strcmp); - + new_count = 0; failed = FALSE; while ((d = readdir(dirp)) != NULL) { if (d->d_name[0] == '.') continue; - /* hash key is the file name without the ":flags" part */ - p = strrchr(d->d_name, ':'); - if (p == d->d_name) - continue; + if (!hash_lookup_full(files, d->d_name, + &orig_key, &orig_value)) { + hash_rec = p_new(pool, struct maildir_hash_rec, 1); + } else { + hash_rec = orig_value; + if (hash_rec->action != MAILDIR_FILE_ACTION_EXPUNGE) { + /* FIXME: duplicate */ + continue; + } + } - value = p_strdup(pool, d->d_name); - key = p == NULL ? value : p_strdup_until(pool, d->d_name, p); - hash_insert(files, key, value); + if (hash_rec->rec == NULL) { + /* new message */ + new_count++; + hash_rec->action = MAILDIR_FILE_ACTION_NEW; + hash_insert(files, p_strdup(pool, d->d_name), hash_rec); + } else if (check_content_changes && + is_file_content_changed(index, rec, + dir, d->d_name)) { + /* file content changed, treat it as new message */ + hash_rec->action = MAILDIR_FILE_ACTION_UPDATE_CONTENT; + + /* make sure filename is not invalidated by expunge + later. the file name may have changed also. */ + hash_insert(files, p_strdup(pool, d->d_name), hash_rec); + } else if (strcmp(orig_key, d->d_name) != 0) { + /* update filename now, flags later */ + hash_rec->action = MAILDIR_FILE_ACTION_UPDATE_FLAGS; + if (!maildir_update_filename(index, hash_rec->rec, + d->d_name)) { + failed = TRUE; + break; + } + } else { + hash_rec->action = MAILDIR_FILE_ACTION_NONE; + } } if (closedir(dirp) < 0) index_file_set_syscall_error(index, dir, "closedir()"); - /* Do we want to check changes in file contents? This slows down - things as we need to do extra stat() for all files. */ - check_content_changes = getenv("MAILDIR_CHECK_CONTENT_CHANGES") != NULL; - - /* now walk through the index syncing and expunging existing mails */ - failed = !maildir_index_sync_files(index, dir, files, - check_content_changes); - if (!failed) { - /* then add the new mails */ - failed = !maildir_index_append_files(index, dir, files); + failed = !maildir_sync_uidlist(index, dir, uidlist, + files, pool, new_count); } - hash_destroy(files); pool_unref(pool); return !failed; } -int maildir_index_sync(struct mail_index *index, - enum mail_lock_type data_lock_type __attr_unused__, - int *changes) +static int maildir_new_scan_first_file(struct mail_index *index, + const char *dir, DIR **dirp, + struct dirent **d) { - struct stat sti, std; + *dirp = opendir(dir); + if (*dirp == NULL) + return index_file_set_syscall_error(index, dir, "opendir()"); + + /* find first file */ + while ((*d = readdir(*dirp)) != NULL) { + if ((*d)->d_name[0] != '.') + break; + } + + if (*d == NULL) { + if (closedir(*dirp) < 0) + index_file_set_syscall_error(index, dir, "closedir()"); + *dirp = NULL; + } + + return TRUE; +} + +static int maildir_index_lock_and_sync(struct mail_index *index, int *changes, + DIR *new_dirp, struct dirent *new_dent, + struct maildir_uidlist **uidlist_r) +{ + struct stat st, std; struct utimbuf ut; - const char *cur_dir, *new_dir; + struct maildir_uidlist *uidlist; + const char *uidlist_path, *cur_dir, *new_dir; time_t index_mtime; + int cur_changed; - i_assert(index->lock_type != MAIL_LOCK_SHARED); - - if (changes != NULL) - *changes = FALSE; + *uidlist_r = uidlist = NULL; if (index->fd == -1) { /* anon-mmaped */ index_mtime = index->file_sync_stamp; } else { - if (fstat(index->fd, &sti) < 0) + if (fstat(index->fd, &st) < 0) return index_set_syscall_error(index, "fstat()"); - index_mtime = sti.st_mtime; + index_mtime = st.st_mtime; } - /* cur/ and new/ directories can have new mail - sync the cur/ first - so it'll be a bit bit faster since we haven't yet added the new - mail. */ cur_dir = t_strconcat(index->mailbox_path, "/cur", NULL); if (stat(cur_dir, &std) < 0) return index_file_set_syscall_error(index, cur_dir, "stat()"); - if (std.st_mtime != index_mtime) { - if (changes != NULL) *changes = TRUE; - if (!maildir_index_sync_dir(index, cur_dir)) + uidlist_path = t_strconcat(index->mailbox_path, + "/" MAILDIR_UIDLIST_NAME, NULL); + if (stat(uidlist_path, &st) < 0) { + if (errno != ENOENT) { + return index_file_set_syscall_error(index, uidlist_path, + "stat()"); + } + + memset(&st, 0, sizeof(st)); + cur_changed = TRUE; + } else { + /* FIXME: save device and inode into index header, so we don't + have to read it every time mailbox is opened */ + cur_changed = index_mtime != std.st_mtime || + st.st_ino != index->uidlist_ino || + !CMP_DEV_T(st.st_dev, index->uidlist_dev); + } + + if (new_dirp != NULL || cur_changed) { + if (maildir_uidlist_try_lock(index) < 0) return FALSE; + + /* we may or may not have succeeded. if we didn't, + just continue by syncing with existing uidlist file */ + + if (!cur_changed && !INDEX_IS_UIDLIST_LOCKED(index)) { + /* just new mails in new/ dir, we can't sync them + if we can't get the lock. */ + return TRUE; + } + + if (!index->set_lock(index, MAIL_LOCK_EXCLUSIVE)) + return FALSE; + + *uidlist_r = uidlist = maildir_uidlist_open(index); + if (uidlist != NULL && + uidlist->uid_validity != index->header->uid_validity) { + /* uidvalidity changed */ + if (!index->rebuilding) { + index_set_corrupted(index, + "UIDVALIDITY changed in uidlist"); + return FALSE; + } + + index->header->uid_validity = uidlist->uid_validity; + } + + if (uidlist != NULL && + index->header->next_uid > uidlist->next_uid) { + index_set_corrupted(index, "index.next_uid (%u) > " + "uidlist.next_uid (%u)", + index->header->next_uid, + uidlist->next_uid); + return FALSE; + } + + if (changes != NULL) + *changes = TRUE; } /* move mail from new/ to cur/ */ - new_dir = t_strconcat(index->mailbox_path, "/new", NULL); - if (stat(new_dir, &std) < 0) - return index_file_set_syscall_error(index, new_dir, "stat()"); - - if (std.st_mtime != index_mtime) { - if (changes != NULL) *changes = TRUE; - - if (!maildir_index_build_dir(index, new_dir, cur_dir)) + if (new_dirp != NULL && INDEX_IS_UIDLIST_LOCKED(index)) { + new_dir = t_strconcat(index->mailbox_path, "/new", NULL); + if (!maildir_index_build_dir(index, new_dir, cur_dir, + new_dirp, new_dent)) return FALSE; - /* set cur/ and new/ directory's timestamp into past to - make sure if someone adds new mail it the new/ dir's - timestamp isn't set to same as cur/ directory's. */ + if (uidlist != NULL) + uidlist->rewrite = TRUE; + + /* set cur/ directory's timestamp into past to make sure we + notice if new mail is moved there */ ut.actime = ut.modtime = ioloop_time-60; if (utime(cur_dir, &ut) < 0) { - return index_file_set_syscall_error(index, cur_dir, - "utime()"); - } - if (utime(new_dir, &ut) < 0) { - return index_file_set_syscall_error(index, new_dir, - "utime()"); + index_file_set_syscall_error(index, cur_dir, "utime()"); + return FALSE; } - /* it's possible that new mail came in just after we - scanned the directory. scan the directory again, this will - update the directory's timestamps so at next sync we'll - always check the new/ dir once more, but at least we can be - sure that no mail got lost. */ - if (!maildir_index_build_dir(index, new_dir, cur_dir)) + /* We have to always scan the cur/ directory to make + sure we don't miss any mails some other non-Dovecot + client may have moved there. FIXME: make it + optional, it's unnecessary with Dovecot-only setup */ + cur_changed = TRUE; + + /* set the cur/ directory's timestamp */ + std.st_mtime = ut.modtime; + } + + if (cur_changed) { + if (!maildir_index_sync_dir(index, cur_dir, uidlist)) return FALSE; } + if (uidlist != NULL && uidlist->next_uid > index->header->next_uid) + index->header->next_uid = uidlist->next_uid; + + if ((new_dirp != NULL || cur_changed) && + (uidlist == NULL || uidlist->rewrite)) { + if (!INDEX_IS_UIDLIST_LOCKED(index)) { + /* there's more new mails, but we need .lock file to + be able to sync them. */ + return TRUE; + } + + if (fstat(index->maildir_lock_fd, &st) < 0) { + return index_file_set_syscall_error(index, uidlist_path, + "fstat()"); + } + + if (!maildir_uidlist_rewrite(index)) + return FALSE; + } + + /* uidlist file synced */ + index->uidlist_ino = st.st_ino; + index->uidlist_dev = st.st_dev; + /* update sync stamp */ - if (stat(cur_dir, &std) < 0) - return index_file_set_syscall_error(index, cur_dir, "stat()"); index->file_sync_stamp = std.st_mtime; - if (index->fd != -1 && index->lock_type == MAIL_LOCK_UNLOCK) { - /* no changes, we need to update index's timestamp + if (index->lock_type == MAIL_LOCK_UNLOCK && !index->anon_mmap) { + /* no changes to index, we need to update it's timestamp ourself to get it changed */ ut.actime = ioloop_time; ut.modtime = index->file_sync_stamp; @@ -334,3 +574,39 @@ return TRUE; } + +int maildir_index_sync(struct mail_index *index, + enum mail_lock_type data_lock_type __attr_unused__, + int *changes) +{ + struct maildir_uidlist *uidlist; + DIR *new_dirp; + struct dirent *new_dent; + const char *new_dir; + int ret; + + i_assert(index->lock_type != MAIL_LOCK_SHARED); + + if (changes != NULL) + *changes = FALSE; + + new_dir = t_strconcat(index->mailbox_path, "/new", NULL); + if (!maildir_new_scan_first_file(index, new_dir, &new_dirp, &new_dent)) + return FALSE; + + ret = maildir_index_lock_and_sync(index, changes, new_dirp, new_dent, + &uidlist); + + if (uidlist != NULL) + maildir_uidlist_close(uidlist); + + if (new_dirp != NULL) { + if (closedir(new_dirp) < 0) { + index_file_set_syscall_error(index, new_dir, + "closedir()"); + } + } + + maildir_uidlist_unlock(index); + return ret; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/lib-index/maildir/maildir-uidlist.c Wed Apr 09 23:10:01 2003 +0300 @@ -0,0 +1,250 @@ +/* Copyright (C) 2003 Timo Sirainen */ + +#include "lib.h" +#include "ioloop.h" +#include "istream.h" +#include "str.h" +#include "write-full.h" +#include "mail-index.h" +#include "mail-index-util.h" +#include "maildir-index.h" +#include "maildir-uidlist.h" + +#include <stdio.h> +#include <sys/stat.h> + +/* how many seconds to wait before overriding uidlist.lock */ +#define UIDLIST_LOCK_STALE_TIMEOUT (60*5) + +int maildir_uidlist_try_lock(struct mail_index *index) +{ + struct stat st; + const char *path; + int fd, i; + + i_assert(!INDEX_IS_UIDLIST_LOCKED(index)); + + path = t_strconcat(index->mailbox_path, + "/" MAILDIR_UIDLIST_NAME ".lock", NULL); + for (i = 0; i < 2; i++) { + fd = open(path, O_WRONLY | O_CREAT | O_EXCL, 0644); + if (fd != -1) + break; + + if (errno != EEXIST) { + index_file_set_syscall_error(index, path, "open()"); + return -1; + } + + /* exists, is it stale? */ + if (stat(path, &st) < 0) { + if (errno == ENOENT) { + /* try again */ + continue; + } + index_file_set_syscall_error(index, path, "stat()"); + return -1; + } + + if (st.st_mtime < ioloop_time - UIDLIST_LOCK_STALE_TIMEOUT) { + if (unlink(path) < 0 && errno != ENOENT) { + return index_file_set_syscall_error(index, path, + "unlink()"); + } + /* try again */ + continue; + } + return 0; + } + + index->maildir_lock_fd = fd; + return 1; +} + +void maildir_uidlist_unlock(struct mail_index *index) +{ + const char *path; + + if (!INDEX_IS_UIDLIST_LOCKED(index)) + return; + + path = t_strconcat(index->mailbox_path, + "/" MAILDIR_UIDLIST_NAME ".lock", NULL); + if (unlink(path) < 0 && errno != ENOENT) + index_file_set_syscall_error(index, path, "unlink()"); + + if (close(index->maildir_lock_fd) < 0) + index_file_set_syscall_error(index, path, "close()"); + index->maildir_lock_fd = -1; +} + +struct maildir_uidlist *maildir_uidlist_open(struct mail_index *index) +{ + const char *path, *line; + struct maildir_uidlist *uidlist; + unsigned int version; + int fd; + + path = t_strconcat(index->mailbox_path, "/" MAILDIR_UIDLIST_NAME, NULL); + fd = open(path, O_RDONLY); + if (fd == -1) { + if (errno != ENOENT) + index_file_set_syscall_error(index, path, "open()"); + return NULL; + } + + uidlist = i_new(struct maildir_uidlist, 1); + uidlist->index = index; + uidlist->fname = i_strdup(path); + uidlist->input = i_stream_create_file(fd, default_pool, 4096, TRUE); + + /* get header */ + line = i_stream_read_next_line(uidlist->input); + if (line == NULL || sscanf(line, "%u %u %u", &version, + &uidlist->uid_validity, + &uidlist->next_uid) != 3 || + version != 1) { + /* broken file */ + (void)unlink(path); + maildir_uidlist_close(uidlist); + return NULL; + } + + return uidlist; +} + +int maildir_uidlist_next(struct maildir_uidlist *uidlist, + struct maildir_uidlist_rec *uid_rec) +{ + const char *line; + unsigned int uid; + + memset(uid_rec, 0, sizeof(*uid_rec)); + + line = i_stream_read_next_line(uidlist->input); + if (line == NULL) + return 0; + + uid = 0; + while (*line >= '0' && *line <= '9') { + uid = uid*10 + (*line - '0'); + line++; + } + + if (uid == 0 || *line != ' ') { + /* invalid file */ + index_set_error(uidlist->index, "Invalid data in file %s", + uidlist->fname); + (void)unlink(uidlist->fname); + return -1; + } + if (uid <= uidlist->last_read_uid) { + index_set_error(uidlist->index, + "UIDs not ordered in file %s (%u > %u)", + uidlist->fname, uid, uidlist->last_read_uid); + (void)unlink(uidlist->fname); + return -1; + } + if (uid >= uidlist->next_uid) { + index_set_error(uidlist->index, + "UID larger than next_uid in file %s " + "(%u >= %u)", uidlist->fname, + uid, uidlist->next_uid); + (void)unlink(uidlist->fname); + return -1; + } + + while (*line == ' ') line++; + + uid_rec->uid = uid; + uid_rec->filename = line; + return 1; +} + +void maildir_uidlist_close(struct maildir_uidlist *uidlist) +{ + i_stream_unref(uidlist->input); + i_free(uidlist->fname); + i_free(uidlist); +} + +int maildir_uidlist_rewrite(struct mail_index *index) +{ + struct mail_index_record *rec; + const char *temp_path, *db_path, *p, *fname; + string_t *str; + size_t len; + int failed = FALSE; + + i_assert(INDEX_IS_UIDLIST_LOCKED(index)); + + if (index->lock_type == MAIL_LOCK_UNLOCK) { + if (!index->set_lock(index, MAIL_LOCK_SHARED)) + return FALSE; + } + + temp_path = t_strconcat(index->mailbox_path, + "/" MAILDIR_UIDLIST_NAME ".lock", NULL); + + str = t_str_new(4096); + str_printfa(str, "1 %u %u\n", + index->header->uid_validity, index->header->next_uid); + + rec = index->lookup(index, 1); + while (rec != NULL) { + fname = maildir_get_location(index, rec); + if (fname == NULL) + break; + + p = strchr(fname, ':'); + len = p == NULL ? strlen(fname) : (size_t)(p-fname); + + if (str_len(str) + MAX_INT_STRLEN + len + 2 >= 4096) { + /* flush buffer */ + if (write_full(index->maildir_lock_fd, + str_data(str), str_len(str)) < 0) { + index_file_set_syscall_error(index, temp_path, + "write_full()"); + break; + } + str_truncate(str, 0); + } + + str_printfa(str, "%u ", rec->uid); + str_append_n(str, fname, len); + str_append_c(str, '\n'); + + rec = index->next(index, rec); + } + + if (write_full(index->maildir_lock_fd, + str_data(str), str_len(str)) < 0) { + index_file_set_syscall_error(index, temp_path, "write_full()"); + failed = TRUE; + } + + if (fdatasync(index->maildir_lock_fd) < 0) { + index_file_set_syscall_error(index, temp_path, "fdatasync()"); + failed = TRUE; + } + if (close(index->maildir_lock_fd) < 0) { + index_file_set_syscall_error(index, temp_path, "close()"); + failed = TRUE; + } + index->maildir_lock_fd = -1; + + if (rec == NULL) { + db_path = t_strconcat(index->mailbox_path, + "/" MAILDIR_UIDLIST_NAME, NULL); + + if (rename(temp_path, db_path) < 0) { + index_set_error(index, "rename(%s, %s) failed: %m", + temp_path, db_path); + failed = TRUE; + } + } + + if (failed) + (void)unlink(temp_path); + return !failed; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/lib-index/maildir/maildir-uidlist.h Wed Apr 09 23:10:01 2003 +0300 @@ -0,0 +1,37 @@ +#ifndef __MAILDIR_UIDLIST_H +#define __MAILDIR_UIDLIST_H + +#define INDEX_IS_UIDLIST_LOCKED(index) \ + ((index)->maildir_lock_fd != -1) + +#define MAILDIR_UIDLIST_NAME "dovecot-uidlist" + +struct maildir_uidlist { + struct mail_index *index; + char *fname; + struct istream *input; + + unsigned int uid_validity, next_uid, last_read_uid; + unsigned int rewrite:1; +}; + +struct maildir_uidlist_rec { + unsigned int uid; + const char *filename; +}; + +int maildir_uidlist_try_lock(struct mail_index *index); +void maildir_uidlist_unlock(struct mail_index *index); +int maildir_uidlist_rewrite(struct mail_index *index); + +struct maildir_uidlist *maildir_uidlist_open(struct mail_index *index); +void maildir_uidlist_close(struct maildir_uidlist *uidlist); + +/* Returns -1 if error, 0 if end of file or 1 if found. + uid_rec.uid is also set to 0 at EOF. This function does sanity checks so + you can be sure that uid_rec.uid is always growing and smaller than + uidlist->next_uid. */ +int maildir_uidlist_next(struct maildir_uidlist *uidlist, + struct maildir_uidlist_rec *uid_rec); + +#endif
--- a/src/lib-storage/index/maildir/maildir-save.c Wed Apr 09 23:07:47 2003 +0300 +++ b/src/lib-storage/index/maildir/maildir-save.c Wed Apr 09 23:10:01 2003 +0300 @@ -2,7 +2,6 @@ #include "lib.h" #include "ioloop.h" -#include "hostpid.h" #include "ostream.h" #include "maildir-index.h" #include "maildir-storage.h" @@ -12,8 +11,6 @@ #include <fcntl.h> #include <utime.h> #include <sys/stat.h> -#include <sys/time.h> -#include <time.h> struct mail_filename { struct mail_filename *next; @@ -30,80 +27,29 @@ struct mail_filename *files; }; -const char *maildir_generate_tmp_filename(const struct timeval *tv) -{ - static unsigned int create_count = 0; - - hostpid_init(); - return t_strdup_printf("%s.P%sQ%uM%s.%s", - dec2str(tv->tv_sec), my_pid, create_count++, - dec2str(tv->tv_usec), my_hostname); -} - -static int maildir_create_tmp(struct mail_storage *storage, const char *dir, - const char **fname) -{ - const char *path, *tmp_fname; - struct stat st; - struct timeval *tv, tv_now; - pool_t pool; - int fd; - - tv = &ioloop_timeval; - pool = pool_alloconly_create("maildir_tmp", 4096); - for (;;) { - p_clear(pool); - tmp_fname = maildir_generate_tmp_filename(tv); - - path = p_strconcat(pool, dir, "/", tmp_fname, NULL); - if (stat(path, &st) < 0 && errno == ENOENT) { - /* doesn't exist */ - fd = open(path, O_WRONLY | O_CREAT | O_EXCL, 0600); - if (fd != -1 || errno != EEXIST) - break; - } - - /* wait and try again - very unlikely */ - sleep(2); - tv = &tv_now; - if (gettimeofday(&tv_now, NULL) < 0) - i_fatal("gettimeofday(): %m"); - } - - *fname = t_strdup(tmp_fname); - if (fd == -1) { - if (ENOSPACE(errno)) { - mail_storage_set_error(storage, - "Not enough disk space"); - } else { - mail_storage_set_critical(storage, - "Can't create file %s: %m", path); - } - } - - pool_unref(pool); - return fd; -} - static const char * -maildir_read_into_tmp(struct mail_storage *storage, const char *dir, +maildir_read_into_tmp(struct index_mailbox *ibox, const char *dir, struct istream *input) { - const char *fname, *path; + const char *path, *fname; struct ostream *output; int fd; - fd = maildir_create_tmp(storage, dir, &fname); + fd = maildir_create_tmp(ibox->index, dir, &path); if (fd == -1) return NULL; + fname = strrchr(path, '/'); + i_assert(fname != NULL); + fname++; + t_push(); output = o_stream_create_file(fd, data_stack_pool, 4096, IO_PRIORITY_DEFAULT, FALSE); o_stream_set_blocking(output, 60000, NULL, NULL); - path = t_strconcat(dir, "/", fname, NULL); - if (!index_storage_save(storage, path, input, output, NULL, NULL)) + if (!index_storage_save(ibox->box.storage, path, input, output, + NULL, NULL)) fname = NULL; o_stream_unref(output); @@ -166,8 +112,7 @@ t_push(); /* create the file into tmp/ directory */ - fname = maildir_read_into_tmp(ctx->ibox->box.storage, - ctx->tmpdir, data); + fname = maildir_read_into_tmp(ctx->ibox, ctx->tmpdir, data); if (fname == NULL) { t_pop(); return FALSE;
--- a/src/lib-storage/index/maildir/maildir-storage.h Wed Apr 09 23:07:47 2003 +0300 +++ b/src/lib-storage/index/maildir/maildir-storage.h Wed Apr 09 23:10:01 2003 +0300 @@ -24,9 +24,6 @@ int maildir_expunge_locked(struct index_mailbox *ibox, int notify); -/* Return new filename base to save into tmp/ */ -const char *maildir_generate_tmp_filename(const struct timeval *tv); - const char *maildir_get_path(struct mail_storage *storage, const char *name); #endif