squat-uidlist.c revision 19e8adccba16ff419f5675b1575358c2956dce83
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen/* Copyright (c) 2007-2008 Dovecot authors, see the included COPYING file */
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen/* set = points to uidlist index number, unset = points to uidlist offset */
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen#define UID_LIST_POINTER_MASK_LIST_IDX 0x80000000
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen#define UIDLIST_PACKED_FLAG_BEGINS_WITH_POINTER 2
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen struct squat_uidlist_build_context *build_ctx;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen ARRAY_TYPE(uint32_t) new_block_offsets, new_block_end_indexes;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen uint32_t list_sizes[UIDLIST_BLOCK_LIST_COUNT];
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainenstatic void squat_uidlist_close(struct squat_uidlist *uidlist);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainenvoid squat_uidlist_delete(struct squat_uidlist *uidlist)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (unlink(uidlist->path) < 0 && errno != ENOENT)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen i_error("unlink(%s) failed: %m", uidlist->path);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainenstatic void squat_uidlist_set_corrupted(struct squat_uidlist *uidlist,
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen i_error("Corrupted squat uidlist file %s: %s", uidlist->path, reason);
a1044a46a8f3512173f4ea2684ef1fc3e61645c7Timo Sirainenuidlist_write_array(struct ostream *output, const uint32_t *uid_list,
a1044a46a8f3512173f4ea2684ef1fc3e61645c7Timo Sirainen unsigned int uid_count, uint32_t packed_flags,
a1044a46a8f3512173f4ea2684ef1fc3e61645c7Timo Sirainen uint32_t offset, bool write_size, uint32_t *size_r)
a1044a46a8f3512173f4ea2684ef1fc3e61645c7Timo Sirainen uint8_t *uidbuf, *bufp, sizebuf[SQUAT_PACK_MAX_SIZE], *sizebufp;
a1044a46a8f3512173f4ea2684ef1fc3e61645c7Timo Sirainen uint8_t listbuf[SQUAT_PACK_MAX_SIZE], *listbufp = listbuf;
a1044a46a8f3512173f4ea2684ef1fc3e61645c7Timo Sirainen uint32_t uid, uid2, prev, base_uid, size_value;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if ((packed_flags & UIDLIST_PACKED_FLAG_BEGINS_WITH_POINTER) != 0)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen /* @UNSAFE */
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen base_uid = uid_list[0] & ~UID_LIST_MASK_RANGE;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen datastack = uid_count < 1024*8/SQUAT_PACK_MAX_SIZE;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen uidbuf = t_malloc(SQUAT_PACK_MAX_SIZE * uid_count);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen uidbuf = i_malloc(SQUAT_PACK_MAX_SIZE * uid_count);
a1044a46a8f3512173f4ea2684ef1fc3e61645c7Timo Sirainen bitmask_len = (uid_list[uid_count-1] - base_uid + 7) / 8 +
a1044a46a8f3512173f4ea2684ef1fc3e61645c7Timo Sirainen i_assert(bitmask_len < SQUAT_PACK_MAX_SIZE*uid_count);
a1044a46a8f3512173f4ea2684ef1fc3e61645c7Timo Sirainen memset(bufp, 0, bitmask_len - (bufp - uidbuf));
a1044a46a8f3512173f4ea2684ef1fc3e61645c7Timo Sirainen if ((uid_list[0] & UID_LIST_MASK_RANGE) == 0) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen for (; i < uid_count; i++) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen i_assert((uid & ~UID_LIST_MASK_RANGE) >= base_uid);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen /* first byte */
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen /* middle bytes */
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen /* last byte */
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen for (i = 0; i < uid_count; i++) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (unlikely((uid & ~UID_LIST_MASK_RANGE) < prev))
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen squat_pack_num(&bufp, uid_list[i+1] - uid - 1);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen o_stream_send(output, sizebuf, sizebufp - sizebuf);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen o_stream_send(output, listbuf, listbufp - listbuf);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainenuidlist_write(struct ostream *output, const struct uidlist_list *list,
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen /* continued UID list */
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen packed_flags |= UIDLIST_PACKED_FLAG_BEGINS_WITH_POINTER;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if ((uid_list[0] & UID_LIST_POINTER_MASK_LIST_IDX) != 0) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen offset = ((uid_list[0] & ~UID_LIST_POINTER_MASK_LIST_IDX) << 1) | 1;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen ret = uidlist_write_array(output, uid_list, uid_count,
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainenstatic void squat_uidlist_map_blocks_set_pointers(struct squat_uidlist *uidlist)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen base = CONST_PTR_OFFSET(uidlist->data, uidlist->hdr.block_list_offset +
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen end_index_size = uidlist->cur_block_count * sizeof(uint32_t);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen end_size = end_index_size + uidlist->cur_block_count * sizeof(uint32_t);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainenstatic int uidlist_file_cache_read(struct squat_uidlist *uidlist,
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (file_cache_read(uidlist->file_cache, offset, size) < 0) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen i_error("read(%s) failed: %m", uidlist->path);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen uidlist->data = file_cache_get_map(uidlist->file_cache,
b650f04c3b2e7dea2295bdbe3239eb82ec03ada0Timo Sirainen squat_uidlist_map_blocks_set_pointers(uidlist);
b650f04c3b2e7dea2295bdbe3239eb82ec03ada0Timo Sirainenstatic int squat_uidlist_map_blocks(struct squat_uidlist *uidlist)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen const struct squat_uidlist_file_header *hdr = &uidlist->hdr;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen uint32_t block_count, blocks_offset, blocks_size, i, verify_count;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen /* empty file */
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen /* get number of blocks */
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (uidlist_file_cache_read(uidlist, hdr->block_list_offset,
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen blocks_offset = hdr->block_list_offset + sizeof(block_count);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen squat_uidlist_set_corrupted(uidlist, "block list outside file");
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen base = CONST_PTR_OFFSET(uidlist->data, hdr->block_list_offset);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen memcpy(&block_count, base, sizeof(block_count));
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen /* map the blocks */
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen blocks_size = block_count * sizeof(uint32_t)*2;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (uidlist_file_cache_read(uidlist, blocks_offset, blocks_size) < 0)
a1044a46a8f3512173f4ea2684ef1fc3e61645c7Timo Sirainen if (blocks_offset + blocks_size > uidlist->data_size) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen squat_uidlist_set_corrupted(uidlist, "block list outside file");
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen squat_uidlist_map_blocks_set_pointers(uidlist);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen /* verify just a couple of the end indexes to make sure they
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen look correct */
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (unlikely(uidlist->cur_block_end_indexes[i-1] >=
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen "block list corrupted");
ce74395e2a932342e04fb682395bcce111574969Timo Sirainenstatic int squat_uidlist_map_header(struct squat_uidlist *uidlist)
ce74395e2a932342e04fb682395bcce111574969Timo Sirainen /* still being built */
a1044a46a8f3512173f4ea2684ef1fc3e61645c7Timo Sirainen if (uidlist->hdr.indexid != uidlist->trie->hdr.indexid) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen /* see if trie was recreated */
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (uidlist->hdr.indexid != uidlist->trie->hdr.indexid) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen squat_uidlist_set_corrupted(uidlist, "wrong indexid");
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (uidlist->hdr.used_file_size < sizeof(uidlist->hdr) ||
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen (uidlist->hdr.used_file_size > uidlist->mmap_size &&
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen squat_uidlist_set_corrupted(uidlist, "broken used_file_size");
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainenstatic void squat_uidlist_unmap(struct squat_uidlist *uidlist)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (munmap(uidlist->mmap_base, uidlist->mmap_size) < 0)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen i_error("munmap(%s) failed: %m", uidlist->path);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainenstatic int squat_uidlist_mmap(struct squat_uidlist *uidlist)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen i_error("fstat(%s) failed: %m", uidlist->path);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (st.st_size < (off_t)sizeof(uidlist->hdr)) {
b650f04c3b2e7dea2295bdbe3239eb82ec03ada0Timo Sirainen squat_uidlist_set_corrupted(uidlist, "File too small");
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen uidlist->mmap_base = mmap(NULL, uidlist->mmap_size,
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen i_error("mmap(%s) failed: %m", uidlist->path);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainenstatic int squat_uidlist_map(struct squat_uidlist *uidlist)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen const struct squat_uidlist_file_header *mmap_hdr = uidlist->mmap_base;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen uidlist->hdr.block_list_offset == mmap_hdr->block_list_offset) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen /* file hasn't changed */
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen uidlist->mmap_size < mmap_hdr->used_file_size) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen /* we want to update blocks mapping, but using the header
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen i_error("pread(%s) failed: %m", uidlist->path);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen i_error("Corrupted %s: File too small", uidlist->path);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (uidlist->file_cache == NULL && uidlist->trie->mmap_disable)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen uidlist->file_cache = file_cache_new(uidlist->fd);
48ce7a375ada1b80545bc6767adb8e8fb23699a8Timo Sirainenstruct squat_uidlist *squat_uidlist_init(struct squat_trie *trie)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen uidlist->path = i_strconcat(trie->path, ".uids", NULL);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainenvoid squat_uidlist_deinit(struct squat_uidlist *uidlist)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainenstatic int squat_uidlist_open(struct squat_uidlist *uidlist)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen memset(&uidlist->hdr, 0, sizeof(uidlist->hdr));
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen i_error("open(%s) failed: %m", uidlist->path);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen return squat_uidlist_map(uidlist) <= 0 ? -1 : 0;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainenstatic void squat_uidlist_close(struct squat_uidlist *uidlist)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen i_error("close(%s) failed: %m", uidlist->path);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainenint squat_uidlist_refresh(struct squat_uidlist *uidlist)
ce74395e2a932342e04fb682395bcce111574969Timo Sirainen /* we assume here that trie is locked, so that we don't need to worry
ce74395e2a932342e04fb682395bcce111574969Timo Sirainen about it when reading the header */
ce74395e2a932342e04fb682395bcce111574969Timo Sirainen uidlist->hdr.indexid != uidlist->trie->hdr.indexid) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainenstatic int squat_uidlist_is_file_stale(struct squat_uidlist *uidlist)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen i_error("stat(%s) failed: %m", uidlist->path);
ce74395e2a932342e04fb682395bcce111574969Timo Sirainen i_error("fstat(%s) failed: %m", uidlist->path);
ce74395e2a932342e04fb682395bcce111574969Timo Sirainenstatic int squat_uidlist_lock(struct squat_uidlist *uidlist)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen ret = file_wait_lock(uidlist->fd, uidlist->path, F_WRLCK,
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen i_error("file_wait_lock(%s) failed: %m", uidlist->path);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen uidlist->fd = open(uidlist->path, O_RDWR | O_CREAT, 0600);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen i_error("open(%s) failed: %m", uidlist->path);
e07677bb15404a3c18ad205efae86d6db31c3150Timo Sirainenstatic int squat_uidlist_open_or_create(struct squat_uidlist *uidlist)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen uidlist->fd = open(uidlist->path, O_RDWR | O_CREAT, 0600);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen i_error("creat(%s) failed: %m", uidlist->path);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen /* broken file, truncate */
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen /* write using 0 until we're finished */
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen memset(&uidlist->hdr, 0, sizeof(uidlist->hdr));
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen i_error("write(%s) failed: %m", uidlist->path);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainenint squat_uidlist_build_init(struct squat_uidlist *uidlist,
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (squat_uidlist_open_or_create(uidlist) < 0) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (lseek(uidlist->fd, uidlist->hdr.used_file_size, SEEK_SET) < 0) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen i_error("lseek(%s) failed: %m", uidlist->path);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen ctx = i_new(struct squat_uidlist_build_context, 1);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen ctx->output = o_stream_create_fd(uidlist->fd, 0, FALSE);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen o_stream_send(ctx->output, &hdr, sizeof(hdr));
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainenuidlist_write_block_list_and_header(struct squat_uidlist_build_context *ctx,
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen unsigned int align, old_block_count, new_block_count;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen ctx->build_hdr.indexid = uidlist->trie->hdr.indexid;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen ctx->build_hdr.used_file_size = output->offset;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen static char null[sizeof(uint32_t)-1] = { 0, };
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen o_stream_send(output, null, sizeof(uint32_t) - align);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen old_block_count = write_old_blocks ? uidlist->cur_block_count : 0;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen block_offset_count = new_block_count + old_block_count;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen o_stream_send(output, &block_offset_count, sizeof(block_offset_count));
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen /* write end indexes */
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen o_stream_send(output, uidlist->cur_block_end_indexes,
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen o_stream_send(output, array_idx(block_end_indexes, 0),
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen /* write offsets */
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen o_stream_send(output, uidlist->cur_block_offsets,
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen o_stream_send(output, array_idx(block_offsets, 0),
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen /* update header - it's written later when trie is locked */
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen ctx->build_hdr.block_list_offset = block_list_offset;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen ctx->build_hdr.used_file_size = output->offset;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainenvoid squat_uidlist_build_flush(struct squat_uidlist_build_context *ctx)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen uint32_t block_offset, block_end_idx, start_offset;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen uint32_t list_sizes[UIDLIST_BLOCK_LIST_COUNT];
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen lists = array_get_modifiable(&ctx->lists, &count);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen /* write the lists and save the written sizes to uid_list[0] */
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen for (i = 0; i < count; i += UIDLIST_BLOCK_LIST_COUNT) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen max = I_MIN(count - i, UIDLIST_BLOCK_LIST_COUNT);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen for (j = 0; j < max; j++) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen "Broken uidlists");
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen block_end_idx = ctx->list_start_idx + i + max;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen array_append(&ctx->block_offsets, &block_offset, 1);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen array_append(&ctx->block_end_indexes, &block_end_idx, 1);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen /* write the full size of the uidlists */
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen squat_pack_num(&bufp, block_offset - start_offset);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen /* write the sizes/flags */
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen for (j = 0; j < max; j++) {
6b4b3e5fe8d9e84f4b1356ee898ca76996a11fe1Timo Sirainen uidlist_write_block_list_and_header(ctx, ctx->output,
e22ec7998afd426c53c658483ce66b6e404e27c6Timo Sirainenint squat_uidlist_build_finish(struct squat_uidlist_build_context *ctx)
e22ec7998afd426c53c658483ce66b6e404e27c6Timo Sirainen o_stream_send(ctx->output, &ctx->build_hdr, sizeof(ctx->build_hdr));
e22ec7998afd426c53c658483ce66b6e404e27c6Timo Sirainen o_stream_seek(ctx->output, ctx->build_hdr.used_file_size);
e22ec7998afd426c53c658483ce66b6e404e27c6Timo Sirainen i_error("write() to %s failed: %m", ctx->uidlist->path);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainenvoid squat_uidlist_build_deinit(struct squat_uidlist_build_context **_ctx)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen struct squat_uidlist_build_context *ctx = *_ctx;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen i_assert(array_count(&ctx->lists) == 0 || ctx->uidlist->corrupted);
ce74395e2a932342e04fb682395bcce111574969Timo Sirainenint squat_uidlist_rebuild_init(struct squat_uidlist_build_context *build_ctx,
b650f04c3b2e7dea2295bdbe3239eb82ec03ada0Timo Sirainen temp_path = t_strconcat(build_ctx->uidlist->path, ".tmp", NULL);
b650f04c3b2e7dea2295bdbe3239eb82ec03ada0Timo Sirainen fd = open(temp_path, O_RDWR | O_TRUNC | O_CREAT, 0600);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen ctx = i_new(struct squat_uidlist_rebuild_context, 1);
b650f04c3b2e7dea2295bdbe3239eb82ec03ada0Timo Sirainen ctx->output = o_stream_create_fd(ctx->fd, 0, FALSE);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen o_stream_send(ctx->output, &hdr, sizeof(hdr));
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen ctx->cur_block_start_offset = ctx->output->offset;
b650f04c3b2e7dea2295bdbe3239eb82ec03ada0Timo Sirainen build_ctx->build_hdr.count / UIDLIST_BLOCK_LIST_COUNT);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen build_ctx->build_hdr.count / UIDLIST_BLOCK_LIST_COUNT);
b650f04c3b2e7dea2295bdbe3239eb82ec03ada0Timo Sirainenuidlist_rebuild_flush_block(struct squat_uidlist_rebuild_context *ctx)
e22ec7998afd426c53c658483ce66b6e404e27c6Timo Sirainen unsigned int i;
b650f04c3b2e7dea2295bdbe3239eb82ec03ada0Timo Sirainen array_append(&ctx->new_block_offsets, &block_offset, 1);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen array_append(&ctx->new_block_end_indexes, &block_end_idx, 1);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen /* this block's contents started from cur_block_start_offset and
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen ended to current offset. write the size of this area. */
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen squat_pack_num(&bufp, block_offset - ctx->cur_block_start_offset);
b650f04c3b2e7dea2295bdbe3239eb82ec03ada0Timo Sirainen /* write the sizes/flags */
e22ec7998afd426c53c658483ce66b6e404e27c6Timo Sirainen ctx->cur_block_start_offset = ctx->output->offset;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainenuint32_t squat_uidlist_rebuild_next(struct squat_uidlist_rebuild_context *ctx,
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen ret = uidlist_write_array(ctx->output, array_idx(uids, 0),
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen squat_uidlist_set_corrupted(ctx->uidlist, "Broken uidlists");
b50234708ad651e98a4198e1b910106b279aae32Timo Sirainen if (++ctx->list_idx == UIDLIST_BLOCK_LIST_COUNT) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainenuint32_t squat_uidlist_rebuild_nextu(struct squat_uidlist_rebuild_context *ctx,
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen unsigned int i, count;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen /* we can use a singleton bitmask */
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen for (i = 0; i < count; i++) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen for (seq = range[i].seq1; seq <= range[i].seq2; seq++)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (count == 1 && range[0].seq1 == range[0].seq2) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen /* single UID */
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen /* convert seq range to our internal representation and use the
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen normal _rebuild_next() to write it */
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen for (i = 0; i < count; i++) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen ret = squat_uidlist_rebuild_next(ctx, &tmp_uids);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainenint squat_uidlist_rebuild_finish(struct squat_uidlist_rebuild_context *ctx,
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen temp_path = t_strconcat(ctx->uidlist->path, ".tmp", NULL);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen ctx->build_ctx->build_hdr.count = ctx->new_count;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen uidlist_write_block_list_and_header(ctx->build_ctx, ctx->output,
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen o_stream_send(ctx->output, &ctx->build_ctx->build_hdr,
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen else if (ctx->output->last_failed_errno != 0) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen i_error("write() to %s failed: %m", temp_path);
if (ret <= 0) {
static struct uidlist_list *
return list;
uint32_t *p;
return uid_list_idx;
return uid_list_idx;
if (uid_list_idx == 0) {
idx = 0;
return uid_list_idx;
return uid_list_idx;
return uid_list_idx;
*p |= UID_LIST_MASK_RANGE;
return uid_list_idx;
*p = uid;
return uid_list_idx;
unsigned int count;
if (count == 0) {
UID_LIST_MASK_RANGE) != 0) {
unsigned int count;
if (count == 0) {
UID_LIST_MASK_RANGE) != 0) {
unsigned int i, j, count;
if (num != 0)
SQUAT_PACK_MAX_SIZE) < 0)
0, uids) < 0)
next_uid = 0;
for (i = 0; i < size; i++) {
base_uid);
if (p == end)
unsigned int idx;
idx++;
max_map_size) < 0)
unsigned int mask;
return idx;
i_unreached();
unsigned int i, count;
int ret;
if (ret == 0) {
for (i = 0; i < count; i++) {
return ret;
int ret = 0;
if (parent_count == 0)
parent_idx = 0;
for (i = 0; i < rel_count; i++) {
while (diff > 0) {
parent_uid++;
diff--;
while (diff > 0) {
parent_uid++;
diff--;
unsigned int *count_r)