Mercurial > dovecot > original-hg > dovecot-1.2
changeset 4094:03e14e3a4610 HEAD
Support accessing saved mails that haven't been committed yet (fixes quota for maildir).
author | Timo Sirainen <timo.sirainen@movial.fi> |
---|---|
date | Mon, 06 Mar 2006 21:05:09 +0200 |
parents | 840d6403ef09 |
children | 2fe0d3ab89c9 |
files | src/lib-storage/index/maildir/maildir-mail.c src/lib-storage/index/maildir/maildir-save.c src/lib-storage/index/maildir/maildir-storage.h |
diffstat | 3 files changed, 144 insertions(+), 61 deletions(-) [+] |
line wrap: on
line diff
--- a/src/lib-storage/index/maildir/maildir-mail.c Mon Mar 06 21:04:25 2006 +0200 +++ b/src/lib-storage/index/maildir/maildir-mail.c Mon Mar 06 21:05:09 2006 +0200 @@ -42,18 +42,25 @@ } static struct istream * -maildir_open_mail(struct maildir_mailbox *mbox, uint32_t uid, bool *deleted) +maildir_open_mail(struct maildir_mailbox *mbox, struct mail *mail, + bool *deleted_r) { - int fd; + const char *path; + int fd = -1; + + *deleted_r = FALSE; - *deleted = FALSE; - - fd = -1; - if (maildir_file_do(mbox, uid, do_open, &fd) < 0) - return NULL; + if (mail->uid != 0) { + if (maildir_file_do(mbox, mail->uid, do_open, &fd) < 0) + return NULL; + } else { + path = maildir_save_file_get_path(mail->transaction, mail->seq); + if (do_open(mbox, path, &fd) <= 0) + return NULL; + } if (fd == -1) { - *deleted = TRUE; + *deleted_r = TRUE; return NULL; } @@ -72,6 +79,7 @@ struct maildir_mailbox *mbox = (struct maildir_mailbox *)mail->ibox; struct index_mail_data *data = &mail->data; struct stat st; + const char *path; int fd; (void)index_mail_get_received_date(_mail); @@ -92,8 +100,13 @@ "fstat(maildir) failed: %m"); return (time_t)-1; } + } else if (_mail->uid != 0) { + if (maildir_file_do(mbox, _mail->uid, do_stat, &st) <= 0) + return (time_t)-1; } else { - if (maildir_file_do(mbox, _mail->uid, do_stat, &st) <= 0) + path = maildir_save_file_get_path(_mail->transaction, + _mail->seq); + if (do_stat(mbox, path, &st) <= 0) return (time_t)-1; } @@ -121,9 +134,15 @@ return data->virtual_size; } - fname = maildir_uidlist_lookup(mbox->uidlist, _mail->uid, &flags); - if (fname == NULL) - return (uoff_t)-1; + if (_mail->uid != 0) { + fname = maildir_uidlist_lookup(mbox->uidlist, _mail->uid, + &flags); + if (fname == NULL) + return (uoff_t)-1; + } else { + fname = maildir_save_file_get_path(_mail->transaction, + _mail->seq); + } /* size can be included in filename */ p = strstr(fname, MAILDIR_EXTRA_SEP_S MAILDIR_EXTRA_VIRTUAL_SIZE "="); @@ -156,8 +175,13 @@ const char *fname, *end; if (field == MAIL_FETCH_UIDL_FILE_NAME) { - fname = maildir_uidlist_lookup(mbox->uidlist, - _mail->uid, &flags); + if (_mail->uid != 0) { + fname = maildir_uidlist_lookup(mbox->uidlist, + _mail->uid, &flags); + } else { + fname = maildir_save_file_get_path(_mail->transaction, + _mail->seq); + } end = strchr(fname, MAILDIR_INFO_SEP); return end == NULL ? fname : t_strdup_until(fname, end); } @@ -179,9 +203,15 @@ if (size != (uoff_t)-1) return size; - fname = maildir_uidlist_lookup(mbox->uidlist, _mail->uid, &flags); - if (fname == NULL) - return (uoff_t)-1; + if (_mail->uid != 0) { + fname = maildir_uidlist_lookup(mbox->uidlist, _mail->uid, + &flags); + if (fname == NULL) + return (uoff_t)-1; + } else { + fname = maildir_save_file_get_path(_mail->transaction, + _mail->seq); + } /* size can be included in filename */ p = strstr(fname, MAILDIR_EXTRA_SEP_S MAILDIR_EXTRA_FILE_SIZE "="); @@ -199,8 +229,14 @@ } if (size == (uoff_t)-1) { - if (maildir_file_do(mbox, _mail->uid, do_stat, &st) <= 0) - return (uoff_t)-1; + if (_mail->uid != 0) { + if (maildir_file_do(mbox, _mail->uid, + do_stat, &st) <= 0) + return (uoff_t)-1; + } else { + if (do_stat(mbox, fname, &st) <= 0) + return (uoff_t)-1; + } size = st.st_size; } @@ -208,7 +244,6 @@ &size, sizeof(size)); data->physical_size = size; return size; - } static struct istream *maildir_mail_get_stream(struct mail *_mail, @@ -221,7 +256,7 @@ bool deleted; if (data->stream == NULL) { - data->stream = maildir_open_mail(mbox, _mail->uid, &deleted); + data->stream = maildir_open_mail(mbox, _mail, &deleted); if (data->stream == NULL) { _mail->expunged = deleted; return NULL;
--- a/src/lib-storage/index/maildir/maildir-save.c Mon Mar 06 21:04:25 2006 +0200 +++ b/src/lib-storage/index/maildir/maildir-save.c Mon Mar 06 21:05:09 2006 +0200 @@ -36,7 +36,7 @@ struct maildir_index_sync_context *sync_ctx; const char *tmpdir, *newdir, *curdir; - struct maildir_filename *files; + struct maildir_filename *files, **files_tail; buffer_t *keywords_buffer; array_t ARRAY_DEFINE(keywords_array, unsigned int); @@ -45,10 +45,11 @@ struct ostream *output; int fd; time_t received_date; - uint32_t seq; + uint32_t first_seq, seq; unsigned int synced:1; unsigned int failed:1; + unsigned int moving:1; unsigned int finished:1; }; @@ -103,6 +104,7 @@ ctx->pool = pool; ctx->mbox = mbox; ctx->trans = t->ictx.trans; + ctx->files_tail = &ctx->files; ctx->tmpdir = p_strconcat(pool, mbox->path, "/tmp", NULL); ctx->newdir = p_strconcat(pool, mbox->path, "/new", NULL); @@ -125,6 +127,17 @@ struct maildir_mailbox *mbox = (struct maildir_mailbox *)t->ictx.ibox; struct maildir_filename *mf; + if (!ctx->synced && want_mail) { + /* we could support adding the missing mails to index, but + currently there's no need. */ + i_assert(ctx->files == NULL); + + if (maildir_storage_sync_force(mbox) < 0) + ctx->failed = TRUE; + else + ctx->synced = TRUE; + } + /* now, we want to be able to rollback the whole append session, so we'll just store the name of this temp file and move it later into new/ or cur/. */ @@ -132,10 +145,13 @@ mf = p_malloc(ctx->pool, sizeof(*mf) + sizeof(unsigned int) * (keywords == NULL ? 0 : keywords->count)); - mf->next = ctx->files; mf->basename = p_strdup(ctx->pool, base_fname); mf->flags = flags; - ctx->files = mf; + + if (*ctx->files_tail != NULL) + (*ctx->files_tail)->next = mf; + *ctx->files_tail = mf; + ctx->files_tail = &mf->next; if (keywords != NULL) { i_assert(sizeof(keywords->idx[0]) == sizeof(unsigned int)); @@ -146,13 +162,6 @@ sizeof(unsigned int) * keywords->count); } - if (!ctx->synced && want_mail) { - if (maildir_storage_sync_force(mbox) < 0) - ctx->failed = TRUE; - else - ctx->synced = TRUE; - } - if (ctx->synced) { /* insert into index */ mail_index_append(ctx->trans, 0, &ctx->seq); @@ -162,6 +171,11 @@ mail_index_update_keywords(ctx->trans, ctx->seq, MODIFY_REPLACE, keywords); } + + if (ctx->first_seq == 0) { + ctx->first_seq = ctx->seq; + i_assert(ctx->files->next == NULL); + } } else { ctx->seq = 0; } @@ -169,6 +183,65 @@ return ctx->seq; } +static const char * +maildir_get_updated_filename(struct maildir_save_context *ctx, + struct maildir_filename *mf) +{ + if (mf->keywords_count == 0) { + if ((mf->flags & MAIL_FLAGS_MASK) == MAIL_RECENT) + return NULL; + return maildir_filename_set_flags(NULL, mf->basename, + mf->flags & MAIL_FLAGS_MASK, + NULL); + } + + buffer_update_const_data(ctx->keywords_buffer, mf + 1, + mf->keywords_count * sizeof(unsigned int)); + return maildir_filename_set_flags( + maildir_sync_get_keywords_sync_ctx(ctx->sync_ctx), + mf->basename, mf->flags & MAIL_FLAGS_MASK, + &ctx->keywords_array); +} + +static const char *maildir_mf_get_path(struct maildir_save_context *ctx, + struct maildir_filename *mf) +{ + const char *fname; + + if (!ctx->moving && (mf->flags & MAILDIR_SAVE_FLAG_HARDLINK) == 0) { + /* file is still in tmp/ */ + return t_strdup_printf("%s/%s", ctx->tmpdir, mf->basename); + } + + /* already moved to new/ or cur/ */ + fname = maildir_get_updated_filename(ctx, mf); + if (fname == NULL) + return t_strdup_printf("%s/%s", ctx->newdir, mf->basename); + else + return t_strdup_printf("%s/%s", ctx->curdir, fname); +} + +const char *maildir_save_file_get_path(struct mailbox_transaction_context *_t, + uint32_t seq) +{ + struct maildir_transaction_context *t = + (struct maildir_transaction_context *)_t; + struct maildir_save_context *ctx = t->save_ctx; + struct maildir_filename *mf; + + i_assert(seq >= ctx->first_seq); + + seq -= ctx->first_seq; + mf = ctx->files; + while (seq > 0) { + mf = mf->next; + i_assert(mf != NULL); + seq--; + } + + return maildir_mf_get_path(ctx, mf); +} + int maildir_save_init(struct mailbox_transaction_context *_t, enum mail_flags flags, struct mail_keywords *keywords, time_t received_date, int timezone_offset __attr_unused__, @@ -328,32 +401,11 @@ (void)maildir_save_finish(_ctx, NULL); } -static const char * -maildir_get_updated_filename(struct maildir_save_context *ctx, - struct maildir_filename *mf) -{ - if (mf->keywords_count == 0) { - if ((mf->flags & MAIL_FLAGS_MASK) == MAIL_RECENT) - return NULL; - return maildir_filename_set_flags(NULL, mf->basename, - mf->flags & MAIL_FLAGS_MASK, - NULL); - } - - buffer_update_const_data(ctx->keywords_buffer, mf + 1, - mf->keywords_count * sizeof(unsigned int)); - return maildir_filename_set_flags( - maildir_sync_get_keywords_sync_ctx(ctx->sync_ctx), - mf->basename, mf->flags & MAIL_FLAGS_MASK, - &ctx->keywords_array); -} - static void maildir_transaction_unlink_copied_files(struct maildir_save_context *ctx, struct maildir_filename *pos) { struct maildir_filename *mf; - const char *path, *dest; /* try to unlink the mails already moved */ for (mf = ctx->files; mf != pos; mf = mf->next) { @@ -361,14 +413,7 @@ continue; t_push(); - dest = maildir_get_updated_filename(ctx, mf); - if (dest != NULL) - path = t_strdup_printf("%s/%s", ctx->curdir, dest); - else { - path = t_strdup_printf("%s/%s", - ctx->newdir, mf->basename); - } - (void)unlink(path); + (void)unlink(maildir_mf_get_path(ctx, mf)); t_pop(); } ctx->files = pos; @@ -410,6 +455,7 @@ /* move them into new/ and/or cur/ */ ret = 0; + ctx->moving = TRUE; for (mf = ctx->files; mf != NULL && ret == 0; mf = mf->next) { t_push(); dest = maildir_get_updated_filename(ctx, mf);
--- a/src/lib-storage/index/maildir/maildir-storage.h Mon Mar 06 21:04:25 2006 +0200 +++ b/src/lib-storage/index/maildir/maildir-storage.h Mon Mar 06 21:05:09 2006 +0200 @@ -129,6 +129,8 @@ uint32_t maildir_save_add(struct maildir_transaction_context *t, const char *base_fname, enum mail_flags flags, struct mail_keywords *keywords, bool want_mail); +const char *maildir_save_file_get_path(struct mailbox_transaction_context *t, + uint32_t seq); int maildir_transaction_save_commit_pre(struct maildir_save_context *ctx); void maildir_transaction_save_commit_post(struct maildir_save_context *ctx);