extension.
--HG--
branch : HEAD
};
struct mail_index_transaction_ext_hdr_update {
- uint32_t ext_id;
- uint16_t offset;
- uint16_t size;
- /* unsigned char data[]; */
+ size_t alloc_size;
+ /* mask is in bytes, not bits */
+ unsigned char *mask;
+ unsigned char *data;
};
struct mail_index_transaction_vfuncs {
unsigned char post_hdr_mask[sizeof(struct mail_index_header)];
ARRAY_DEFINE(ext_hdr_updates,
- struct mail_index_transaction_ext_hdr_update *);
+ struct mail_index_transaction_ext_hdr_update);
ARRAY_DEFINE(ext_rec_updates, ARRAY_TYPE(seq_array));
ARRAY_DEFINE(ext_resizes, struct mail_transaction_ext_intro);
ARRAY_DEFINE(ext_resets, struct mail_transaction_ext_reset);
void mail_index_transaction_reset(struct mail_index_transaction *t)
{
ARRAY_TYPE(seq_array) *recs;
- struct mail_index_transaction_ext_hdr_update **ext_hdrs;
+ struct mail_index_transaction_ext_hdr_update *ext_hdrs;
unsigned i, count;
if (array_is_created(&t->ext_rec_updates)) {
if (array_is_created(&t->ext_hdr_updates)) {
ext_hdrs = array_get_modifiable(&t->ext_hdr_updates, &count);
- for (i = 0; i < count; i++)
- i_free(ext_hdrs[i]);
+ for (i = 0; i < count; i++) {
+ i_free(ext_hdrs[i].data);
+ i_free(ext_hdrs[i].mask);
+ }
array_free(&t->ext_hdr_updates);
}
}
}
if (array_is_created(&t->ext_hdr_updates)) {
- struct mail_index_transaction_ext_hdr_update *const *hdr;
+ const struct mail_index_transaction_ext_hdr_update *hdr;
hdr = array_get(&t->ext_hdr_updates, &count);
for (i = 0; i < count; i++) {
- if (hdr[i] != NULL)
+ if (hdr[i].alloc_size > 0)
return TRUE;
}
}
if (array_is_created(&t->ext_hdr_updates) &&
ext_id < array_count(&t->ext_hdr_updates)) {
/* if extension headers have been updated, clear them */
- struct mail_index_transaction_ext_hdr_update **hdr;
+ struct mail_index_transaction_ext_hdr_update *hdr;
hdr = array_idx_modifiable(&t->ext_hdr_updates, ext_id);
- if (*hdr != NULL)
- i_free_and_null(*hdr);
+ if (hdr->alloc_size > 0) {
+ i_free_and_null(hdr->mask);
+ i_free_and_null(hdr->data);
+ }
+ hdr->alloc_size = 0;
}
if (array_is_created(&t->ext_resets) &&
ext_id < array_count(&t->ext_resets)) {
uint32_t ext_id, size_t offset,
const void *data, size_t size)
{
- struct mail_index_transaction_ext_hdr_update *hdr, **pos;
+ struct mail_index_transaction_ext_hdr_update *hdr;
+ size_t new_size;
- hdr = i_malloc(sizeof(*hdr) + size);
- hdr->ext_id = ext_id;
- hdr->offset = offset;
- hdr->size = size;
- memcpy(hdr + 1, data, size);
+ i_assert(offset <= (uint16_t)-1 && size <= (uint16_t)-1 &&
+ offset + size <= (uint16_t)-1);
if (!array_is_created(&t->ext_hdr_updates))
i_array_init(&t->ext_hdr_updates, ext_id + 2);
- pos = array_idx_modifiable(&t->ext_hdr_updates, ext_id);
- if (*pos != NULL) {
- i_panic("mail_index_update_header_ext() doesn't currently "
- "support multiple updates to the same ext header");
+ hdr = array_idx_modifiable(&t->ext_hdr_updates, ext_id);
+ if (hdr->alloc_size < offset || hdr->alloc_size - offset < size) {
+ i_assert(size < (size_t)-1 - offset);
+ new_size = nearest_power(offset + size);
+ hdr->mask = i_realloc(hdr->mask, hdr->alloc_size, new_size);
+ hdr->data = i_realloc(hdr->data, hdr->alloc_size, new_size);
+ hdr->alloc_size = new_size;
}
- *pos = hdr;
+ memset(hdr->mask + offset, 1, size);
+ memcpy(hdr->data + offset, data, size);
t->log_ext_updates = TRUE;
}
static void
log_append_ext_hdr_update(struct log_append_context *ctx,
- struct mail_index_transaction_ext_hdr_update *hdr)
+ const struct mail_index_transaction_ext_hdr_update *hdr)
{
- struct mail_transaction_ext_hdr_update *trans_hdr;
buffer_t *buf;
- unsigned int hdr_size;
-
- hdr_size = sizeof(*trans_hdr) + hdr->size + 4;
- buf = buffer_create_static_hard(pool_datastack_create(), hdr_size);
- trans_hdr = buffer_append_space_unsafe(buf, sizeof(*trans_hdr));
- trans_hdr->offset = hdr->offset;
- trans_hdr->size = hdr->size;
- buffer_append(buf, hdr + 1, hdr->size);
+ const unsigned char *data, *mask;
+ struct mail_transaction_ext_hdr_update u;
+ uint16_t offset;
+ bool started = FALSE;
+
+ memset(&u, 0, sizeof(u));
+
+ data = hdr->data;
+ mask = hdr->mask;
+
+ buf = buffer_create_dynamic(pool_datastack_create(), 256);
+ for (offset = 0; offset <= hdr->alloc_size; offset++) {
+ if (offset < hdr->alloc_size && mask[offset] != 0) {
+ if (!started) {
+ u.offset = offset;
+ started = TRUE;
+ }
+ } else {
+ if (started) {
+ u.size = offset - u.offset;
+ buffer_append(buf, &u, sizeof(u));
+ buffer_append(buf, data + u.offset, u.size);
+ started = FALSE;
+ }
+ }
+ }
if (buf->used % 4 != 0)
buffer_append_zero(buf, 4 - buf->used % 4);
log_append_buffer(ctx, buf, NULL, MAIL_TRANSACTION_EXT_HDR_UPDATE);
{
struct mail_index_transaction *t = ctx->trans;
const struct mail_transaction_ext_intro *resize;
- struct mail_index_transaction_ext_hdr_update *const *hdrs;
+ const struct mail_index_transaction_ext_hdr_update *hdrs;
struct mail_transaction_ext_reset ext_reset;
unsigned int update_count, resize_count, ext_count = 0;
unsigned int hdrs_count, reset_id_count, reset_count;
(ext_id < update_count &&
array_is_created(&update[ext_id])) ||
ext_reset.new_reset_id != 0 ||
- (ext_id < hdrs_count && hdrs[ext_id] != NULL)) {
+ (ext_id < hdrs_count && hdrs[ext_id].alloc_size > 0)) {
reset_id = ext_id < reset_id_count &&
ext_reset.new_reset_id == 0 ?
reset_ids[ext_id] : 0;
log_append_buffer(ctx, buf, NULL,
MAIL_TRANSACTION_EXT_RESET);
}
- if (ext_id < hdrs_count && hdrs[ext_id] != NULL) {
+ if (ext_id < hdrs_count && hdrs[ext_id].alloc_size > 0) {
T_BEGIN {
- log_append_ext_hdr_update(ctx, hdrs[ext_id]);
+ log_append_ext_hdr_update(ctx, &hdrs[ext_id]);
} T_END;
}
}