From: Timo Sirainen Date: Thu, 16 Apr 2026 15:38:41 +0000 (+0200) Subject: [PATCH 3/5] lib-compression: Add o_stream_deflate_reset_dict() X-Git-Tag: archive/raspbian/1%2.4.1+dfsg1-6+rpi1+deb13u7^2~11 X-Git-Url: https://dgit.raspbian.org/?a=commitdiff_plain;h=3cdde39d062c981d237eeff44a6d291b3da2bcc6;p=dovecot.git [PATCH 3/5] lib-compression: Add o_stream_deflate_reset_dict() New public function that locates the deflate ostream in the parent chain (transparently handles rawlog wrappers) and schedules a Z_FULL_FLUSH on the next uncork/flush. Z_FULL_FLUSH emits all buffered data and then resets the deflate dictionary, so subsequent compressed output cannot reference data from before the call. Adds a pending_dict_reset flag to struct zlib_ostream. The flag persists through partial flush retries and is cleared only once the full flush loop completes. Gbp-Pq: Name 0003-lib-compression-Add-o_stream_deflate_reset_dict.patch --- diff --git a/src/lib-compression/ostream-zlib.c b/src/lib-compression/ostream-zlib.c index 6aeccbf..5bc41d0 100644 --- a/src/lib-compression/ostream-zlib.c +++ b/src/lib-compression/ostream-zlib.c @@ -23,6 +23,7 @@ struct zlib_ostream { bool gz:1; bool flushed:1; + bool pending_dict_reset:1; }; struct zlib_settings { @@ -252,8 +253,14 @@ o_stream_zlib_send_flush(struct zlib_ostream *zstream, bool final) if ((ret = o_stream_zlib_send_outbuf(zstream)) <= 0) return ret; - flush = final ? Z_FINISH : - (!zstream->gz ? Z_SYNC_FLUSH : Z_NO_FLUSH); + if (final) + flush = Z_FINISH; + else if (zstream->gz) + flush = Z_NO_FLUSH; + else if (zstream->pending_dict_reset) + flush = Z_FULL_FLUSH; + else + flush = Z_SYNC_FLUSH; i_assert(zstream->outbuf_used == 0); do { @@ -283,6 +290,10 @@ o_stream_zlib_send_flush(struct zlib_ostream *zstream, bool final) } } while (zs->avail_out != sizeof(zstream->outbuf)); + /* Z_FULL_FLUSH completes here; clear the request so subsequent flushes + use the normal Z_SYNC_FLUSH again. */ + zstream->pending_dict_reset = FALSE; + if (final) { if (o_stream_zlib_send_gz_trailer(zstream) < 0) return -1; @@ -443,3 +454,25 @@ struct ostream *o_stream_create_deflate_auto(struct ostream *output, struct even { return o_stream_create_zlib_auto(output, event, FALSE); } +void o_stream_deflate_reset_dict(struct ostream *_output) +{ + struct ostream_private *stream = _output->real_stream; + + /* Traverse the ostream parent chain to find the deflate ostream. + The caller may pass a rawlog-wrapped stream or the deflate stream + itself; either way we find it by its sendv function pointer. */ + while (stream != NULL) { + if (stream->sendv == o_stream_zlib_sendv) { + struct zlib_ostream *zstream = + container_of(stream, struct zlib_ostream, ostream); + i_assert(!zstream->gz); + zstream->pending_dict_reset = TRUE; + o_stream_set_flush_pending( + &zstream->ostream.ostream, TRUE); + return; + } + stream = (stream->parent != NULL) ? + stream->parent->real_stream : NULL; + } + /* No deflate ostream found in the chain – nothing to reset. */ +} diff --git a/src/lib-compression/ostream-zlib.h b/src/lib-compression/ostream-zlib.h index 9738e36..4db62fd 100644 --- a/src/lib-compression/ostream-zlib.h +++ b/src/lib-compression/ostream-zlib.h @@ -7,4 +7,11 @@ struct ostream *o_stream_create_bz2_auto(struct ostream *output, struct event *e struct ostream *o_stream_create_lz4_auto(struct ostream *output, struct event *event); struct ostream *o_stream_create_zstd_auto(struct ostream *output, struct event *event); +/* Reset the deflate compression dictionary so that subsequent compressed + output cannot reference data from before this call. Pass any ostream in + the chain (e.g. a rawlog wrapper); the function locates the deflate stream + internally. Safe to call when compression is not active – it is a no-op + in that case. */ +void o_stream_deflate_reset_dict(struct ostream *output); + #endif