]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
maildir: Delay removal of corrupted sizes from maildir filenames
authorTimo Sirainen <timo.sirainen@open-xchange.com>
Wed, 8 Oct 2025 13:05:40 +0000 (16:05 +0300)
committertimo.sirainen <timo.sirainen@open-xchange.com>
Mon, 13 Oct 2025 12:30:58 +0000 (12:30 +0000)
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.

src/lib-storage/index/maildir/Makefile.am
src/lib-storage/index/maildir/maildir-mail.c
src/lib-storage/index/maildir/maildir-mail.h [new file with mode: 0644]
src/lib-storage/index/maildir/maildir-storage.c

index a18a7b5ce24fd65e37d988990e8ef8c845a08de6..5d076e739bea7d7531c7c4579ca2e1546d821f04 100644 (file)
@@ -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 \
index 0ee1ea131d97cce1647f108706616d68c6f8d1b0..ca357a14140701af0e57e52adfee7cabf3c78da9 100644 (file)
@@ -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 <unistd.h>
 #include <sys/stat.h>
 
+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 (file)
index 0000000..49e26c5
--- /dev/null
@@ -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
index f81a4546ac949f8deb606b328e7bcef7e1dcad6e..128fd679c0c10be64213ad4e43da0c629abf124d 100644 (file)
@@ -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 <sys/stat.h>
 
@@ -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,