From: Timo Sirainen Date: Wed, 8 Oct 2025 13:05:40 +0000 (+0300) Subject: maildir: Delay removal of corrupted sizes from maildir filenames X-Git-Tag: 2.4.2~107 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=47c53c4e5d88177870af6db7e52dd76efcb6eff4;p=thirdparty%2Fdovecot%2Fcore.git maildir: Delay removal of corrupted sizes from maildir filenames The size removal functions were doing many distruptive things, which could have caused crashes on various places where maildir_mail_set_cache_corrupted() was called from. Delay the fixing to a few safe locations. --- diff --git a/src/lib-storage/index/maildir/Makefile.am b/src/lib-storage/index/maildir/Makefile.am index a18a7b5ce2..5d076e739b 100644 --- a/src/lib-storage/index/maildir/Makefile.am +++ b/src/lib-storage/index/maildir/Makefile.am @@ -29,6 +29,7 @@ headers = \ maildir-filename.h \ maildir-filename-flags.h \ maildir-keywords.h \ + maildir-mail.h \ maildir-storage.h \ maildir-settings.h \ maildir-sync.h \ diff --git a/src/lib-storage/index/maildir/maildir-mail.c b/src/lib-storage/index/maildir/maildir-mail.c index 0ee1ea131d..ca357a1414 100644 --- a/src/lib-storage/index/maildir/maildir-mail.c +++ b/src/lib-storage/index/maildir/maildir-mail.c @@ -3,7 +3,7 @@ #include "lib.h" #include "istream.h" #include "nfs-workarounds.h" -#include "index-mail.h" +#include "maildir-mail.h" #include "maildir-storage.h" #include "maildir-filename.h" #include "maildir-uidlist.h" @@ -14,6 +14,8 @@ #include #include +static void maildir_mail_fix_corruption(struct mail *_mail); + struct maildir_open_context { int fd; char *path; @@ -606,6 +608,7 @@ maildir_mail_get_stream(struct mail *_mail, bool get_body ATTR_UNUSED, struct index_mail_data *data = &mail->data; bool deleted; + maildir_mail_fix_corruption(_mail); if (data->stream == NULL) { data->stream = maildir_open_mail(mbox, _mail, &deleted); if (data->stream == NULL) { @@ -761,20 +764,40 @@ maildir_mail_remove_sizes_from_filename(struct mail *mail, (void)maildir_file_do(mbox, mail->uid, do_fix_size, &ctx); } +static void maildir_mail_fix_corruption(struct mail *_mail) +{ + struct maildir_mail *mail = + container_of(_mail, struct maildir_mail, imail.mail.mail); + + if (mail->corrupted_field == 0) + return; + + mail->corrupted_field = 0; + maildir_mail_remove_sizes_from_uidlist(_mail); + maildir_mail_remove_sizes_from_filename(_mail, mail->corrupted_field); +} + static void maildir_mail_set_cache_corrupted(struct mail *_mail, enum mail_fetch_field field, const char *reason) { + struct maildir_mail *mail = + container_of(_mail, struct maildir_mail, imail.mail.mail); + if (field == MAIL_FETCH_PHYSICAL_SIZE || - field == MAIL_FETCH_VIRTUAL_SIZE) { - maildir_mail_remove_sizes_from_uidlist(_mail); - maildir_mail_remove_sizes_from_filename(_mail, field); - } + field == MAIL_FETCH_VIRTUAL_SIZE) + mail->corrupted_field = field; index_mail_set_cache_corrupted(_mail, field, reason); } +static void maildir_mail_close(struct mail *_mail) +{ + maildir_mail_fix_corruption(_mail); + index_mail_close(_mail); +} + struct mail_vfuncs maildir_mail_vfuncs = { - index_mail_close, + maildir_mail_close, index_mail_free, index_mail_set_seq, index_mail_set_uid, diff --git a/src/lib-storage/index/maildir/maildir-mail.h b/src/lib-storage/index/maildir/maildir-mail.h new file mode 100644 index 0000000000..49e26c5aa6 --- /dev/null +++ b/src/lib-storage/index/maildir/maildir-mail.h @@ -0,0 +1,11 @@ +#ifndef MAILDIR_MAIL_H +#define MAILDIR_MAIL_H + +#include "index-mail.h" + +struct maildir_mail { + struct index_mail imail; + enum mail_fetch_field corrupted_field; +}; + +#endif diff --git a/src/lib-storage/index/maildir/maildir-storage.c b/src/lib-storage/index/maildir/maildir-storage.c index f81a4546ac..128fd679c0 100644 --- a/src/lib-storage/index/maildir/maildir-storage.c +++ b/src/lib-storage/index/maildir/maildir-storage.c @@ -12,7 +12,7 @@ #include "maildir-uidlist.h" #include "maildir-keywords.h" #include "maildir-sync.h" -#include "index-mail.h" +#include "maildir-mail.h" #include @@ -698,6 +698,22 @@ static enum mail_flags maildir_get_private_flags_mask(struct mailbox *box) return mbox->_private_flags_mask; } +static struct mail * +maildir_mail_alloc(struct mailbox_transaction_context *t, + enum mail_fetch_field wanted_fields, + struct mailbox_header_lookup_ctx *wanted_headers) +{ + struct maildir_mail *mail; + pool_t pool; + + pool = pool_alloconly_create("mail", 2048); + mail = p_new(pool, struct maildir_mail, 1); + + index_mail_init(&mail->imail, t, wanted_fields, + wanted_headers, pool, NULL); + return &mail->imail.mail.mail; +} + bool maildir_is_backend_readonly(struct maildir_mailbox *mbox) { if (!mbox->backend_readonly_set) { @@ -763,7 +779,7 @@ struct mailbox maildir_mailbox = { index_transaction_commit, index_transaction_rollback, maildir_get_private_flags_mask, - index_mail_alloc, + maildir_mail_alloc, index_storage_search_init, index_storage_search_deinit, index_storage_search_next_nonblock,