]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib-index: Delete dovecot.index.cache during purging if it becomes too large
authorTimo Sirainen <timo.sirainen@open-xchange.com>
Mon, 17 Apr 2023 21:08:40 +0000 (00:08 +0300)
committeraki.tuomi <aki.tuomi@open-xchange.com>
Thu, 24 Aug 2023 14:57:55 +0000 (14:57 +0000)
This only happens if the file was already too large before the purging
happens. This mainly fixes assert-crashes caused by old huge >1GB cache
files.

Fixes:
Panic: file mail-index-util.c: line 10 (mail_index_uint32_to_offset): assertion failed: (offset < 0x40000000)

src/lib-index/mail-cache-purge.c

index 2cb11316e76caef92321902beb2db8c42ea1277a..fa5874d959c8d6ab43b616a179721f28128930db 100644 (file)
@@ -326,10 +326,14 @@ mail_cache_copy(struct mail_cache *cache, struct mail_index_transaction *trans,
        }
        i_assert(orig_fields_count == cache->fields_count);
 
-       hdr.record_count = record_count;
-       hdr.field_header_offset = mail_index_uint32_to_offset(output->offset);
-       mail_cache_purge_get_fields(&ctx, used_fields_count);
-       o_stream_nsend(output, ctx.buffer->data, ctx.buffer->used);
+       bool file_too_large =
+               output->offset > cache->index->optimization_set.cache.max_size;
+       if (!file_too_large) {
+               hdr.record_count = record_count;
+               hdr.field_header_offset = mail_index_uint32_to_offset(output->offset);
+               mail_cache_purge_get_fields(&ctx, used_fields_count);
+               o_stream_nsend(output, ctx.buffer->data, ctx.buffer->used);
+       }
 
        hdr.backwards_compat_used_file_size = output->offset;
        buffer_free(&ctx.buffer);
@@ -342,8 +346,17 @@ mail_cache_copy(struct mail_cache *cache, struct mail_index_transaction *trans,
        mail_cache_view_close(&cache_view);
        mail_index_view_close(&view);
 
-       if (o_stream_finish(output) < 0) {
-               mail_cache_set_syscall_error(cache, "write()");
+       if (file_too_large || o_stream_finish(output) < 0) {
+               if (!file_too_large) {
+                       errno = output->stream_errno;
+                       mail_cache_set_syscall_error(cache, "write()");
+               } else {
+                       /* start from a new empty cache file */
+                       mail_index_set_error(cache->index,
+                               "Cache file %s: File is too large - deleting",
+                               cache->filepath);
+                       i_unlink(cache->filepath);
+               }
                o_stream_destroy(&output);
                array_free(ext_offsets);
                return -1;