diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 09:51:24 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 09:51:24 +0000 |
commit | f7548d6d28c313cf80e6f3ef89aed16a19815df1 (patch) | |
tree | a3f6f2a3f247293bee59ecd28e8cd8ceb6ca064a /src/lib-index/mail-index-util.c | |
parent | Initial commit. (diff) | |
download | dovecot-upstream.tar.xz dovecot-upstream.zip |
Adding upstream version 1:2.3.19.1+dfsg1.upstream/1%2.3.19.1+dfsg1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r-- | src/lib-index/mail-index-util.c | 138 |
1 files changed, 138 insertions, 0 deletions
diff --git a/src/lib-index/mail-index-util.c b/src/lib-index/mail-index-util.c new file mode 100644 index 0000000..2b27ae1 --- /dev/null +++ b/src/lib-index/mail-index-util.c @@ -0,0 +1,138 @@ +/* Copyright (c) 2003-2018 Dovecot authors, see the included COPYING file */ + +#include "lib.h" +#include "array.h" +#include "bsearch-insert-pos.h" +#include "mail-index-private.h" + +uint32_t mail_index_uint32_to_offset(uint32_t offset) +{ + i_assert(offset < 0x40000000); + i_assert((offset & 3) == 0); + + offset >>= 2; + offset = 0x00000080 | ((offset & 0x0000007f)) | + 0x00008000 | ((offset & 0x00003f80) >> 7 << 8) | + 0x00800000 | ((offset & 0x001fc000) >> 14 << 16) | + 0x80000000 | ((offset & 0x0fe00000) >> 21 << 24); + + return cpu32_to_be(offset); +} + +uint32_t mail_index_offset_to_uint32(uint32_t offset) +{ + offset = be32_to_cpu(offset); + + if ((offset & 0x80808080) != 0x80808080) + return 0; + + return (((offset & 0x0000007f)) | + ((offset & 0x00007f00) >> 8 << 7) | + ((offset & 0x007f0000) >> 16 << 14) | + ((offset & 0x7f000000) >> 24 << 21)) << 2; +} + +void mail_index_pack_num(uint8_t **p, uint32_t num) +{ + /* number continues as long as the highest bit is set */ + while (num >= 0x80) { + **p = (num & 0x7f) | 0x80; + *p += 1; + num >>= 7; + } + + **p = num; + *p += 1; +} + +int mail_index_unpack_num(const uint8_t **p, const uint8_t *end, + uint32_t *num_r) +{ + const uint8_t *c = *p; + uint32_t value = 0; + unsigned int bits = 0; + + for (;;) { + if (unlikely(c == end)) { + /* we should never see EOF */ + *num_r = 0; + return -1; + } + + value |= (*c & 0x7f) << bits; + if (*c < 0x80) + break; + + bits += 7; + c++; + } + + if (unlikely(bits >= 32)) { + /* broken input */ + *p = end; + *num_r = 0; + return -1; + } + + *p = c + 1; + *num_r = value; + return 0; +} + +static int mail_index_seq_record_cmp(const uint32_t *key_seq, + const uint32_t *data_seq) +{ + return (int)*key_seq - (int)*data_seq; +} + +bool mail_index_seq_array_lookup(const ARRAY_TYPE(seq_array) *array, + uint32_t seq, unsigned int *idx_r) +{ + return array_bsearch_insert_pos(array, &seq, + mail_index_seq_record_cmp, idx_r); +} + +void mail_index_seq_array_alloc(ARRAY_TYPE(seq_array) *array, + size_t record_size) +{ + size_t aligned_record_size = (record_size + 3) & ~3U; + + i_assert(!array_is_created(array)); + + array_create(array, default_pool, + sizeof(uint32_t) + aligned_record_size, + 1024 / (sizeof(uint32_t) + aligned_record_size)); +} + +bool mail_index_seq_array_add(ARRAY_TYPE(seq_array) *array, uint32_t seq, + const void *record, size_t record_size, + void *old_record) +{ + void *p; + unsigned int idx, aligned_record_size; + + /* records need to be 32bit aligned */ + aligned_record_size = (record_size + 3) & ~3U; + + if (!array_is_created(array)) + mail_index_seq_array_alloc(array, record_size); + i_assert(array->arr.element_size == sizeof(seq) + aligned_record_size); + + if (mail_index_seq_array_lookup(array, seq, &idx)) { + /* already there, update */ + p = array_idx_modifiable(array, idx); + if (old_record != NULL) { + /* save the old record before overwriting it */ + memcpy(old_record, PTR_OFFSET(p, sizeof(seq)), + record_size); + } + memcpy(PTR_OFFSET(p, sizeof(seq)), record, record_size); + return TRUE; + } else { + /* insert */ + p = array_insert_space(array, idx); + memcpy(p, &seq, sizeof(seq)); + memcpy(PTR_OFFSET(p, sizeof(seq)), record, record_size); + return FALSE; + } +} |