squat-uidlist.c revision 19e8adccba16ff419f5675b1575358c2956dce83
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen/* Copyright (c) 2007-2008 Dovecot authors, see the included COPYING file */
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen#include "lib.h"
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen#include "array.h"
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen#include "bsearch-insert-pos.h"
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen#include "file-cache.h"
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen#include "file-lock.h"
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen#include "read-full.h"
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen#include "write-full.h"
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen#include "ostream.h"
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen#include "squat-trie-private.h"
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen#include "squat-uidlist.h"
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen#include <stdio.h>
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen#include <sys/stat.h>
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen#include <sys/mman.h>
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen#define UIDLIST_LIST_SIZE 31
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen#define UIDLIST_BLOCK_LIST_COUNT 100
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen#define UID_LIST_MASK_RANGE 0x80000000
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
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
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen#define UIDLIST_PACKED_FLAG_BITMASK 1
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen#define UIDLIST_PACKED_FLAG_BEGINS_WITH_POINTER 2
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainenstruct uidlist_list {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen uint32_t uid_count:31;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen uint32_t uid_begins_with_pointer:1;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen uint32_t uid_list[UIDLIST_LIST_SIZE];
ce74395e2a932342e04fb682395bcce111574969Timo Sirainen};
a1044a46a8f3512173f4ea2684ef1fc3e61645c7Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainenstruct squat_uidlist {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen struct squat_trie *trie;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen char *path;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen int fd;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen struct file_cache *file_cache;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen struct file_lock *file_lock;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen uoff_t locked_file_size;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen void *mmap_base;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen size_t mmap_size;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen struct squat_uidlist_file_header hdr;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
7fa451bfbbe759379b4f8d3f289c77a0d51b8d07Timo Sirainen const void *data;
ce74395e2a932342e04fb682395bcce111574969Timo Sirainen size_t data_size;
ce74395e2a932342e04fb682395bcce111574969Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen unsigned int cur_block_count;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen const uint32_t *cur_block_offsets;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen const uint32_t *cur_block_end_indexes;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen size_t max_size;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen unsigned int corrupted:1;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen unsigned int building:1;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen};
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainenstruct squat_uidlist_build_context {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen struct squat_uidlist *uidlist;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen struct ostream *output;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen ARRAY_TYPE(uint32_t) block_offsets;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen ARRAY_TYPE(uint32_t) block_end_indexes;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen ARRAY_DEFINE(lists, struct uidlist_list);
ce74395e2a932342e04fb682395bcce111574969Timo Sirainen uint32_t list_start_idx;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen struct squat_uidlist_file_header build_hdr;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen unsigned int need_reopen:1;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen};
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainenstruct squat_uidlist_rebuild_context {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen struct squat_uidlist *uidlist;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen struct squat_uidlist_build_context *build_ctx;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen int fd;
e22ec7998afd426c53c658483ce66b6e404e27c6Timo Sirainen struct ostream *output;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen ARRAY_TYPE(uint32_t) new_block_offsets, new_block_end_indexes;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen uoff_t cur_block_start_offset;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen uint32_t list_sizes[UIDLIST_BLOCK_LIST_COUNT];
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen uint32_t next_uid_list_idx;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen unsigned int list_idx;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen unsigned int new_count;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen};
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainenstatic void squat_uidlist_close(struct squat_uidlist *uidlist);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainenvoid squat_uidlist_delete(struct squat_uidlist *uidlist)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen{
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (unlink(uidlist->path) < 0 && errno != ENOENT)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen i_error("unlink(%s) failed: %m", uidlist->path);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen}
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainenstatic void squat_uidlist_set_corrupted(struct squat_uidlist *uidlist,
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen const char *reason)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen{
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (uidlist->corrupted)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen return;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen uidlist->corrupted = TRUE;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen i_error("Corrupted squat uidlist file %s: %s", uidlist->path, reason);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen squat_trie_delete(uidlist->trie);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen}
a1044a46a8f3512173f4ea2684ef1fc3e61645c7Timo Sirainen
a1044a46a8f3512173f4ea2684ef1fc3e61645c7Timo Sirainenstatic int
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{
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;
a1044a46a8f3512173f4ea2684ef1fc3e61645c7Timo Sirainen unsigned int i, bitmask_len, uid_list_len;
a1044a46a8f3512173f4ea2684ef1fc3e61645c7Timo Sirainen unsigned int idx, max_idx, mask;
a1044a46a8f3512173f4ea2684ef1fc3e61645c7Timo Sirainen bool datastack;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen int num;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if ((packed_flags & UIDLIST_PACKED_FLAG_BEGINS_WITH_POINTER) != 0)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen squat_pack_num(&listbufp, offset);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
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 if (datastack)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen uidbuf = t_malloc(SQUAT_PACK_MAX_SIZE * uid_count);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen else
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen uidbuf = i_malloc(SQUAT_PACK_MAX_SIZE * uid_count);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen bufp = uidbuf;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen squat_pack_num(&bufp, base_uid);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
a1044a46a8f3512173f4ea2684ef1fc3e61645c7Timo Sirainen bitmask_len = (uid_list[uid_count-1] - base_uid + 7) / 8 +
a1044a46a8f3512173f4ea2684ef1fc3e61645c7Timo Sirainen (bufp - uidbuf);
a1044a46a8f3512173f4ea2684ef1fc3e61645c7Timo Sirainen if (bitmask_len < uid_count) {
a1044a46a8f3512173f4ea2684ef1fc3e61645c7Timo Sirainen bitmask_build:
a1044a46a8f3512173f4ea2684ef1fc3e61645c7Timo Sirainen i_assert(bitmask_len < SQUAT_PACK_MAX_SIZE*uid_count);
a1044a46a8f3512173f4ea2684ef1fc3e61645c7Timo Sirainen
a1044a46a8f3512173f4ea2684ef1fc3e61645c7Timo Sirainen memset(bufp, 0, bitmask_len - (bufp - uidbuf));
a1044a46a8f3512173f4ea2684ef1fc3e61645c7Timo Sirainen if ((uid_list[0] & UID_LIST_MASK_RANGE) == 0) {
a1044a46a8f3512173f4ea2684ef1fc3e61645c7Timo Sirainen i = 1;
a1044a46a8f3512173f4ea2684ef1fc3e61645c7Timo Sirainen uid = i == uid_count ? 0 : uid_list[i];
a1044a46a8f3512173f4ea2684ef1fc3e61645c7Timo Sirainen } else {
a1044a46a8f3512173f4ea2684ef1fc3e61645c7Timo Sirainen i = 0;
a1044a46a8f3512173f4ea2684ef1fc3e61645c7Timo Sirainen uid = uid_list[0] + 1;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen }
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen base_uid++;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen for (; i < uid_count; i++) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen i_assert((uid & ~UID_LIST_MASK_RANGE) >= base_uid);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if ((uid & UID_LIST_MASK_RANGE) == 0) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen uid -= base_uid;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen uid2 = uid;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen } else {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen uid &= ~UID_LIST_MASK_RANGE;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen uid -= base_uid;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen uid2 = uid_list[i+1] - base_uid;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen i++;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen }
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (uid2 - uid < 3*8) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen for (; uid <= uid2; uid++)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen bufp[uid / 8] |= 1 << (uid % 8);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen } else {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen /* first byte */
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen idx = uid / 8;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen num = uid % 8;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (num != 0) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen uid += 8 - num;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen for (mask = 0; num < 8; num++)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen mask |= 1 << num;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen bufp[idx++] |= mask;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen }
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen /* middle bytes */
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen num = uid2 % 8;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen max_idx = idx + (uid2 - num - uid)/8;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen for (; idx < max_idx; idx++, uid += 8)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen bufp[idx] = 0xff;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen /* last byte */
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen for (mask = 0; num >= 0; num--)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen mask |= 1 << num;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen bufp[idx] |= mask;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen }
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen uid = i+1 == uid_count ? 0 : uid_list[i+1];
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen }
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen uid_list_len = bitmask_len;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen packed_flags |= UIDLIST_PACKED_FLAG_BITMASK;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen } else {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen bufp = uidbuf;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen prev = 0;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen for (i = 0; i < uid_count; i++) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen uid = uid_list[i];
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (unlikely((uid & ~UID_LIST_MASK_RANGE) < prev))
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen return -1;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if ((uid & UID_LIST_MASK_RANGE) == 0) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen squat_pack_num(&bufp, (uid - prev) << 1);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen prev = uid + 1;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen } else {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen uid &= ~UID_LIST_MASK_RANGE;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen squat_pack_num(&bufp, 1 | (uid - prev) << 1);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen squat_pack_num(&bufp, uid_list[i+1] - uid - 1);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen prev = uid_list[i+1] + 1;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen i++;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen }
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen }
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen uid_list_len = bufp - uidbuf;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (uid_list_len > bitmask_len) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen bufp = uidbuf;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen squat_pack_num(&bufp, base_uid);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen goto bitmask_build;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen }
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen }
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen size_value = ((uid_list_len +
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen (listbufp - listbuf)) << 2) | packed_flags;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (write_size) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen sizebufp = sizebuf;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen squat_pack_num(&sizebufp, size_value);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen o_stream_send(output, sizebuf, sizebufp - sizebuf);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen }
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen o_stream_send(output, listbuf, listbufp - listbuf);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen o_stream_send(output, uidbuf, uid_list_len);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (!datastack)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen i_free(uidbuf);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen *size_r = size_value;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen return 0;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen}
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainenstatic int
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainenuidlist_write(struct ostream *output, const struct uidlist_list *list,
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen bool write_size, uint32_t *size_r)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen{
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen const uint32_t *uid_list = list->uid_list;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen uint8_t buf[SQUAT_PACK_MAX_SIZE], *bufp;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen uint32_t uid_count = list->uid_count;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen uint32_t packed_flags = 0;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen uint32_t offset = 0;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen int ret;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (list->uid_begins_with_pointer) {
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 if (list->uid_count == 1) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen bufp = buf;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen squat_pack_num(&bufp, offset);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen o_stream_send(output, buf, bufp - buf);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen *size_r = (bufp - buf) << 2 | packed_flags;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen return 0;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen }
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen } else {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen i_assert(list->uid_count > 1);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen i_assert(output->offset > uid_list[0]);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen offset = (output->offset - uid_list[0]) << 1;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen }
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen uid_list++;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen uid_count--;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen }
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen T_BEGIN {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen ret = uidlist_write_array(output, uid_list, uid_count,
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen packed_flags, offset,
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen write_size, size_r);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen } T_END;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen return ret;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen}
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainenstatic void squat_uidlist_map_blocks_set_pointers(struct squat_uidlist *uidlist)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen{
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen const void *base;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen size_t end_index_size, end_size;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen base = CONST_PTR_OFFSET(uidlist->data, uidlist->hdr.block_list_offset +
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen sizeof(uint32_t));
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
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 Sirainen if (end_size <= uidlist->data_size) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen uidlist->cur_block_end_indexes = base;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen uidlist->cur_block_offsets =
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen CONST_PTR_OFFSET(base, end_index_size);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen } else {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen uidlist->cur_block_end_indexes = NULL;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen uidlist->cur_block_offsets = NULL;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen }
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen}
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainenstatic int uidlist_file_cache_read(struct squat_uidlist *uidlist,
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen size_t offset, size_t size)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen{
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (uidlist->file_cache == NULL)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen return 0;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (file_cache_read(uidlist->file_cache, offset, size) < 0) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen i_error("read(%s) failed: %m", uidlist->path);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen return -1;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen }
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen uidlist->data = file_cache_get_map(uidlist->file_cache,
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen &uidlist->data_size);
b650f04c3b2e7dea2295bdbe3239eb82ec03ada0Timo Sirainen squat_uidlist_map_blocks_set_pointers(uidlist);
b650f04c3b2e7dea2295bdbe3239eb82ec03ada0Timo Sirainen return 0;
b650f04c3b2e7dea2295bdbe3239eb82ec03ada0Timo Sirainen}
b650f04c3b2e7dea2295bdbe3239eb82ec03ada0Timo Sirainen
b650f04c3b2e7dea2295bdbe3239eb82ec03ada0Timo Sirainenstatic int squat_uidlist_map_blocks(struct squat_uidlist *uidlist)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen{
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen const struct squat_uidlist_file_header *hdr = &uidlist->hdr;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen const void *base;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen uint32_t block_count, blocks_offset, blocks_size, i, verify_count;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (hdr->block_list_offset == 0) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen /* empty file */
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen uidlist->cur_block_count = 0;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen return 1;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen }
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen /* get number of blocks */
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (uidlist_file_cache_read(uidlist, hdr->block_list_offset,
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen sizeof(block_count)) < 0)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen return -1;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen blocks_offset = hdr->block_list_offset + sizeof(block_count);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (blocks_offset > uidlist->data_size) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen squat_uidlist_set_corrupted(uidlist, "block list outside file");
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen return 0;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen }
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen base = CONST_PTR_OFFSET(uidlist->data, hdr->block_list_offset);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen memcpy(&block_count, base, sizeof(block_count));
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
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 return -1;
a1044a46a8f3512173f4ea2684ef1fc3e61645c7Timo Sirainen if (blocks_offset + blocks_size > uidlist->data_size) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen squat_uidlist_set_corrupted(uidlist, "block list outside file");
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen return 0;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen }
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen uidlist->cur_block_count = block_count;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen squat_uidlist_map_blocks_set_pointers(uidlist);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen /* verify just a couple of the end indexes to make sure they
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen look correct */
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen verify_count = I_MIN(block_count, 8);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen for (i = 1; i < verify_count; i++) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (unlikely(uidlist->cur_block_end_indexes[i-1] >=
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen uidlist->cur_block_end_indexes[i])) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen squat_uidlist_set_corrupted(uidlist,
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen "block list corrupted");
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen return 0;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen }
ce74395e2a932342e04fb682395bcce111574969Timo Sirainen }
ce74395e2a932342e04fb682395bcce111574969Timo Sirainen return 1;
ce74395e2a932342e04fb682395bcce111574969Timo Sirainen}
ce74395e2a932342e04fb682395bcce111574969Timo Sirainen
ce74395e2a932342e04fb682395bcce111574969Timo Sirainenstatic int squat_uidlist_map_header(struct squat_uidlist *uidlist)
ce74395e2a932342e04fb682395bcce111574969Timo Sirainen{
ce74395e2a932342e04fb682395bcce111574969Timo Sirainen if (uidlist->hdr.indexid == 0) {
ce74395e2a932342e04fb682395bcce111574969Timo Sirainen /* still being built */
a1044a46a8f3512173f4ea2684ef1fc3e61645c7Timo Sirainen return 1;
a1044a46a8f3512173f4ea2684ef1fc3e61645c7Timo Sirainen }
a1044a46a8f3512173f4ea2684ef1fc3e61645c7Timo Sirainen if (uidlist->hdr.indexid != uidlist->trie->hdr.indexid) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen /* see if trie was recreated */
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen squat_trie_refresh(uidlist->trie);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen }
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (uidlist->hdr.indexid != uidlist->trie->hdr.indexid) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen squat_uidlist_set_corrupted(uidlist, "wrong indexid");
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen return 0;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen }
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (uidlist->hdr.used_file_size < sizeof(uidlist->hdr) ||
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen (uidlist->hdr.used_file_size > uidlist->mmap_size &&
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen uidlist->mmap_base != NULL)) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen squat_uidlist_set_corrupted(uidlist, "broken used_file_size");
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen return 0;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen }
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen return squat_uidlist_map_blocks(uidlist);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen}
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainenstatic void squat_uidlist_unmap(struct squat_uidlist *uidlist)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen{
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (uidlist->mmap_size != 0) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (munmap(uidlist->mmap_base, uidlist->mmap_size) < 0)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen i_error("munmap(%s) failed: %m", uidlist->path);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen uidlist->mmap_base = NULL;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen uidlist->mmap_size = 0;
a1044a46a8f3512173f4ea2684ef1fc3e61645c7Timo Sirainen }
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen uidlist->cur_block_count = 0;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen uidlist->cur_block_end_indexes = NULL;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen uidlist->cur_block_offsets = NULL;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen}
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainenstatic int squat_uidlist_mmap(struct squat_uidlist *uidlist)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen{
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen struct stat st;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (fstat(uidlist->fd, &st) < 0) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen i_error("fstat(%s) failed: %m", uidlist->path);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen return -1;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen }
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (st.st_size < (off_t)sizeof(uidlist->hdr)) {
b650f04c3b2e7dea2295bdbe3239eb82ec03ada0Timo Sirainen if (st.st_size == 0)
b650f04c3b2e7dea2295bdbe3239eb82ec03ada0Timo Sirainen return 0;
b650f04c3b2e7dea2295bdbe3239eb82ec03ada0Timo Sirainen squat_uidlist_set_corrupted(uidlist, "File too small");
b650f04c3b2e7dea2295bdbe3239eb82ec03ada0Timo Sirainen return -1;
b650f04c3b2e7dea2295bdbe3239eb82ec03ada0Timo Sirainen }
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen squat_uidlist_unmap(uidlist);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen uidlist->mmap_size = st.st_size;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen uidlist->mmap_base = mmap(NULL, uidlist->mmap_size,
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen PROT_READ | PROT_WRITE,
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen MAP_SHARED, uidlist->fd, 0);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (uidlist->mmap_base == MAP_FAILED) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen uidlist->data = uidlist->mmap_base = NULL;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen uidlist->data_size = uidlist->mmap_size = 0;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen i_error("mmap(%s) failed: %m", uidlist->path);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen return -1;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen }
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen uidlist->data = uidlist->mmap_base;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen uidlist->data_size = uidlist->mmap_size;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen return 0;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen}
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainenstatic int squat_uidlist_map(struct squat_uidlist *uidlist)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen{
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen const struct squat_uidlist_file_header *mmap_hdr = uidlist->mmap_base;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen int ret;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (mmap_hdr != NULL && !uidlist->building &&
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen uidlist->hdr.block_list_offset == mmap_hdr->block_list_offset) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen /* file hasn't changed */
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen return 1;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen }
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (!uidlist->trie->mmap_disable) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (mmap_hdr == NULL || uidlist->building ||
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen uidlist->mmap_size < mmap_hdr->used_file_size) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (squat_uidlist_mmap(uidlist) < 0)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen return -1;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen }
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (!uidlist->building) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen memcpy(&uidlist->hdr, uidlist->mmap_base,
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen sizeof(uidlist->hdr));
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen }
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen } else if (uidlist->building) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen /* we want to update blocks mapping, but using the header
f0e811f0e306bb20d3da9c26353bdd5669132f29Timo Sirainen in memory */
f0e811f0e306bb20d3da9c26353bdd5669132f29Timo Sirainen } else {
f0e811f0e306bb20d3da9c26353bdd5669132f29Timo Sirainen ret = pread_full(uidlist->fd, &uidlist->hdr,
f0e811f0e306bb20d3da9c26353bdd5669132f29Timo Sirainen sizeof(uidlist->hdr), 0);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (ret <= 0) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (ret < 0) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen i_error("pread(%s) failed: %m", uidlist->path);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen return -1;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen }
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen i_error("Corrupted %s: File too small", uidlist->path);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen return 0;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen }
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen uidlist->data = NULL;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen uidlist->data_size = 0;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen }
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (uidlist->file_cache == NULL && uidlist->trie->mmap_disable)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen uidlist->file_cache = file_cache_new(uidlist->fd);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen return squat_uidlist_map_header(uidlist);
48ce7a375ada1b80545bc6767adb8e8fb23699a8Timo Sirainen}
48ce7a375ada1b80545bc6767adb8e8fb23699a8Timo Sirainen
48ce7a375ada1b80545bc6767adb8e8fb23699a8Timo Sirainenstruct squat_uidlist *squat_uidlist_init(struct squat_trie *trie)
48ce7a375ada1b80545bc6767adb8e8fb23699a8Timo Sirainen{
48ce7a375ada1b80545bc6767adb8e8fb23699a8Timo Sirainen struct squat_uidlist *uidlist;
b650f04c3b2e7dea2295bdbe3239eb82ec03ada0Timo Sirainen
b650f04c3b2e7dea2295bdbe3239eb82ec03ada0Timo Sirainen uidlist = i_new(struct squat_uidlist, 1);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen uidlist->trie = trie;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen uidlist->path = i_strconcat(trie->path, ".uids", NULL);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen uidlist->fd = -1;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen return uidlist;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen}
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainenvoid squat_uidlist_deinit(struct squat_uidlist *uidlist)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen{
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen squat_uidlist_close(uidlist);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen i_free(uidlist->path);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen i_free(uidlist);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen}
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainenstatic int squat_uidlist_open(struct squat_uidlist *uidlist)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen{
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen squat_uidlist_close(uidlist);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen uidlist->fd = open(uidlist->path, O_RDWR);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (uidlist->fd == -1) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (errno == ENOENT) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen memset(&uidlist->hdr, 0, sizeof(uidlist->hdr));
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen return 0;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen }
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen i_error("open(%s) failed: %m", uidlist->path);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen return -1;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen }
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen return squat_uidlist_map(uidlist) <= 0 ? -1 : 0;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen}
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainenstatic void squat_uidlist_close(struct squat_uidlist *uidlist)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen{
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen i_assert(!uidlist->building);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen squat_uidlist_unmap(uidlist);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (uidlist->file_cache != NULL)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen file_cache_free(&uidlist->file_cache);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (uidlist->file_lock != NULL)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen file_lock_free(&uidlist->file_lock);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (uidlist->fd != -1) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (close(uidlist->fd) < 0)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen i_error("close(%s) failed: %m", uidlist->path);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen uidlist->fd = -1;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen }
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen uidlist->corrupted = FALSE;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen}
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainenint squat_uidlist_refresh(struct squat_uidlist *uidlist)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen{
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 if (uidlist->fd == -1 ||
ce74395e2a932342e04fb682395bcce111574969Timo Sirainen uidlist->hdr.indexid != uidlist->trie->hdr.indexid) {
ce74395e2a932342e04fb682395bcce111574969Timo Sirainen if (squat_uidlist_open(uidlist) < 0)
ce74395e2a932342e04fb682395bcce111574969Timo Sirainen return -1;
ce74395e2a932342e04fb682395bcce111574969Timo Sirainen } else {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (squat_uidlist_map(uidlist) <= 0)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen return -1;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen }
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen return 0;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen}
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainenstatic int squat_uidlist_is_file_stale(struct squat_uidlist *uidlist)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen{
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen struct stat st, st2;
ce74395e2a932342e04fb682395bcce111574969Timo Sirainen
ce74395e2a932342e04fb682395bcce111574969Timo Sirainen i_assert(uidlist->fd != -1);
ce74395e2a932342e04fb682395bcce111574969Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (stat(uidlist->path, &st) < 0) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (errno == ENOENT)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen return 1;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen i_error("stat(%s) failed: %m", uidlist->path);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen return -1;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen }
ce74395e2a932342e04fb682395bcce111574969Timo Sirainen if (fstat(uidlist->fd, &st2) < 0) {
ce74395e2a932342e04fb682395bcce111574969Timo Sirainen i_error("fstat(%s) failed: %m", uidlist->path);
ce74395e2a932342e04fb682395bcce111574969Timo Sirainen return -1;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen }
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen uidlist->locked_file_size = st2.st_size;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
ce74395e2a932342e04fb682395bcce111574969Timo Sirainen return st.st_ino == st2.st_ino &&
ce74395e2a932342e04fb682395bcce111574969Timo Sirainen CMP_DEV_T(st.st_dev, st2.st_dev) ? 0 : 1;
ce74395e2a932342e04fb682395bcce111574969Timo Sirainen}
ce74395e2a932342e04fb682395bcce111574969Timo Sirainen
ce74395e2a932342e04fb682395bcce111574969Timo Sirainenstatic int squat_uidlist_lock(struct squat_uidlist *uidlist)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen{
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen int ret;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
ce74395e2a932342e04fb682395bcce111574969Timo Sirainen for (;;) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen i_assert(uidlist->fd != -1);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen i_assert(uidlist->file_lock == NULL);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen ret = file_wait_lock(uidlist->fd, uidlist->path, F_WRLCK,
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen uidlist->trie->lock_method,
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen SQUAT_TRIE_LOCK_TIMEOUT,
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen &uidlist->file_lock);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (ret == 0) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen i_error("file_wait_lock(%s) failed: %m", uidlist->path);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen return 0;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen }
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (ret < 0)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen return -1;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen ret = squat_uidlist_is_file_stale(uidlist);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (ret == 0)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen break;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen file_unlock(&uidlist->file_lock);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (ret < 0)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen return -1;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen squat_uidlist_close(uidlist);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen uidlist->fd = open(uidlist->path, O_RDWR | O_CREAT, 0600);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (uidlist->fd == -1) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen i_error("open(%s) failed: %m", uidlist->path);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen return -1;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen }
e07677bb15404a3c18ad205efae86d6db31c3150Timo Sirainen }
e07677bb15404a3c18ad205efae86d6db31c3150Timo Sirainen return 1;
e07677bb15404a3c18ad205efae86d6db31c3150Timo Sirainen}
e07677bb15404a3c18ad205efae86d6db31c3150Timo Sirainen
e07677bb15404a3c18ad205efae86d6db31c3150Timo Sirainenstatic int squat_uidlist_open_or_create(struct squat_uidlist *uidlist)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen{
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen int ret;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (uidlist->fd == -1) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen uidlist->fd = open(uidlist->path, O_RDWR | O_CREAT, 0600);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (uidlist->fd == -1) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen i_error("creat(%s) failed: %m", uidlist->path);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen return -1;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen }
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen }
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (squat_uidlist_lock(uidlist) <= 0)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen return -1;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (uidlist->locked_file_size != 0) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if ((ret = squat_uidlist_map(uidlist)) < 0)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen return -1;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (ret == 0) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen /* broken file, truncate */
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (ftruncate(uidlist->fd, 0) < 0) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen i_error("ftruncate(%s) failed: %m",
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen uidlist->path);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen return -1;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen }
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen uidlist->locked_file_size = 0;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen }
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen }
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (uidlist->locked_file_size == 0) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen /* write using 0 until we're finished */
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen memset(&uidlist->hdr, 0, sizeof(uidlist->hdr));
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (write_full(uidlist->fd, &uidlist->hdr,
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen sizeof(uidlist->hdr)) < 0) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen i_error("write(%s) failed: %m", uidlist->path);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen return -1;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen }
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen }
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen return 0;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen}
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainenint squat_uidlist_build_init(struct squat_uidlist *uidlist,
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen struct squat_uidlist_build_context **ctx_r)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen{
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen struct squat_uidlist_build_context *ctx;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen i_assert(!uidlist->building);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (squat_uidlist_open_or_create(uidlist) < 0) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (uidlist->file_lock != NULL)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen file_unlock(&uidlist->file_lock);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen return -1;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen }
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 if (uidlist->file_lock != NULL)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen file_unlock(&uidlist->file_lock);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen return -1;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen }
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen ctx = i_new(struct squat_uidlist_build_context, 1);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen ctx->uidlist = uidlist;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen ctx->output = o_stream_create_fd(uidlist->fd, 0, FALSE);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (ctx->output->offset == 0) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen struct squat_uidlist_file_header hdr;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen memset(&hdr, 0, sizeof(hdr));
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen o_stream_send(ctx->output, &hdr, sizeof(hdr));
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen }
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen o_stream_cork(ctx->output);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen i_array_init(&ctx->lists, 10240);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen i_array_init(&ctx->block_offsets, 128);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen i_array_init(&ctx->block_end_indexes, 128);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen ctx->list_start_idx = uidlist->hdr.count;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen ctx->build_hdr = uidlist->hdr;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen uidlist->building = TRUE;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen *ctx_r = ctx;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen return 0;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen}
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainenstatic void
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainenuidlist_write_block_list_and_header(struct squat_uidlist_build_context *ctx,
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen struct ostream *output,
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen ARRAY_TYPE(uint32_t) *block_offsets,
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen ARRAY_TYPE(uint32_t) *block_end_indexes,
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen bool write_old_blocks)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen{
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen struct squat_uidlist *uidlist = ctx->uidlist;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen unsigned int align, old_block_count, new_block_count;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen uint32_t block_offset_count;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen uoff_t block_list_offset;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen i_assert(uidlist->trie->hdr.indexid != 0);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen ctx->build_hdr.indexid = uidlist->trie->hdr.indexid;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (array_count(block_end_indexes) == 0) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen ctx->build_hdr.used_file_size = output->offset;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen ctx->build_hdr.block_list_offset = 0;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen uidlist->hdr = ctx->build_hdr;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen return;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen }
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen align = output->offset % sizeof(uint32_t);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (align != 0) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen static char null[sizeof(uint32_t)-1] = { 0, };
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen o_stream_send(output, null, sizeof(uint32_t) - align);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen }
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen block_list_offset = output->offset;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen new_block_count = array_count(block_offsets);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen old_block_count = write_old_blocks ? uidlist->cur_block_count : 0;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
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 old_block_count * sizeof(uint32_t));
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen o_stream_send(output, array_idx(block_end_indexes, 0),
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen new_block_count * sizeof(uint32_t));
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen /* write offsets */
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen o_stream_send(output, uidlist->cur_block_offsets,
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen old_block_count * sizeof(uint32_t));
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen o_stream_send(output, array_idx(block_offsets, 0),
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen new_block_count * sizeof(uint32_t));
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen o_stream_flush(output);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
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 Sirainen uidlist->hdr = ctx->build_hdr;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen}
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainenvoid squat_uidlist_build_flush(struct squat_uidlist_build_context *ctx)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen{
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen struct uidlist_list *lists;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen uint8_t buf[SQUAT_PACK_MAX_SIZE], *bufp;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen unsigned int i, j, count, max;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen uint32_t block_offset, block_end_idx, start_offset;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen uint32_t list_sizes[UIDLIST_BLOCK_LIST_COUNT];
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen size_t mem_size;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (ctx->uidlist->corrupted)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen return;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen lists = array_get_modifiable(&ctx->lists, &count);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (count == 0)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen return;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
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 start_offset = ctx->output->offset;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen max = I_MIN(count - i, UIDLIST_BLOCK_LIST_COUNT);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen for (j = 0; j < max; j++) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (uidlist_write(ctx->output, &lists[i+j],
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen FALSE, &list_sizes[j]) < 0) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen squat_uidlist_set_corrupted(ctx->uidlist,
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen "Broken uidlists");
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen return;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen }
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen }
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen block_offset = ctx->output->offset;
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
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen /* write the full size of the uidlists */
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen bufp = buf;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen squat_pack_num(&bufp, block_offset - start_offset);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen o_stream_send(ctx->output, buf, bufp - buf);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen /* write the sizes/flags */
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen for (j = 0; j < max; j++) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen bufp = buf;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen squat_pack_num(&bufp, list_sizes[j]);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen o_stream_send(ctx->output, buf, bufp - buf);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen }
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen }
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen mem_size = ctx->lists.arr.buffer->used +
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen ctx->block_offsets.arr.buffer->used +
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen ctx->block_end_indexes.arr.buffer->used;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (ctx->uidlist->max_size < mem_size)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen ctx->uidlist->max_size = mem_size;
6b4b3e5fe8d9e84f4b1356ee898ca76996a11fe1Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen ctx->list_start_idx += count;
6b4b3e5fe8d9e84f4b1356ee898ca76996a11fe1Timo Sirainen array_clear(&ctx->lists);
6b4b3e5fe8d9e84f4b1356ee898ca76996a11fe1Timo Sirainen
6b4b3e5fe8d9e84f4b1356ee898ca76996a11fe1Timo Sirainen uidlist_write_block_list_and_header(ctx, ctx->output,
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen &ctx->block_offsets,
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen &ctx->block_end_indexes, TRUE);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen (void)squat_uidlist_map(ctx->uidlist);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
e22ec7998afd426c53c658483ce66b6e404e27c6Timo Sirainen array_clear(&ctx->block_offsets);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen array_clear(&ctx->block_end_indexes);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen}
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
e22ec7998afd426c53c658483ce66b6e404e27c6Timo Sirainenint squat_uidlist_build_finish(struct squat_uidlist_build_context *ctx)
e22ec7998afd426c53c658483ce66b6e404e27c6Timo Sirainen{
e22ec7998afd426c53c658483ce66b6e404e27c6Timo Sirainen if (ctx->uidlist->corrupted)
e22ec7998afd426c53c658483ce66b6e404e27c6Timo Sirainen return -1;
e22ec7998afd426c53c658483ce66b6e404e27c6Timo Sirainen
e22ec7998afd426c53c658483ce66b6e404e27c6Timo Sirainen o_stream_seek(ctx->output, 0);
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 o_stream_flush(ctx->output);
e22ec7998afd426c53c658483ce66b6e404e27c6Timo Sirainen
e22ec7998afd426c53c658483ce66b6e404e27c6Timo Sirainen if (ctx->output->last_failed_errno != 0) {
e22ec7998afd426c53c658483ce66b6e404e27c6Timo Sirainen errno = ctx->output->last_failed_errno;
e22ec7998afd426c53c658483ce66b6e404e27c6Timo Sirainen i_error("write() to %s failed: %m", ctx->uidlist->path);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen return -1;
ce74395e2a932342e04fb682395bcce111574969Timo Sirainen }
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen return 0;
ce74395e2a932342e04fb682395bcce111574969Timo Sirainen}
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainenvoid squat_uidlist_build_deinit(struct squat_uidlist_build_context **_ctx)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen{
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen struct squat_uidlist_build_context *ctx = *_ctx;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
6b4b3e5fe8d9e84f4b1356ee898ca76996a11fe1Timo Sirainen *_ctx = NULL;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen i_assert(array_count(&ctx->lists) == 0 || ctx->uidlist->corrupted);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen i_assert(ctx->uidlist->building);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen ctx->uidlist->building = FALSE;
ce74395e2a932342e04fb682395bcce111574969Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen file_unlock(&ctx->uidlist->file_lock);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (ctx->need_reopen)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen (void)squat_uidlist_open(ctx->uidlist);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen array_free(&ctx->block_offsets);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen array_free(&ctx->block_end_indexes);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen array_free(&ctx->lists);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen o_stream_unref(&ctx->output);
6b4b3e5fe8d9e84f4b1356ee898ca76996a11fe1Timo Sirainen i_free(ctx);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen}
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
ce74395e2a932342e04fb682395bcce111574969Timo Sirainenint squat_uidlist_rebuild_init(struct squat_uidlist_build_context *build_ctx,
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen bool compress,
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen struct squat_uidlist_rebuild_context **ctx_r)
ce74395e2a932342e04fb682395bcce111574969Timo Sirainen{
ce74395e2a932342e04fb682395bcce111574969Timo Sirainen struct squat_uidlist_rebuild_context *ctx;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen struct squat_uidlist_file_header hdr;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen const char *temp_path;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen int fd;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (build_ctx->build_hdr.link_count == 0)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen return 0;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
e22ec7998afd426c53c658483ce66b6e404e27c6Timo Sirainen if (!compress) {
e22ec7998afd426c53c658483ce66b6e404e27c6Timo Sirainen if (build_ctx->build_hdr.link_count <
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen build_ctx->build_hdr.count*2/3)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen return 0;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen }
b650f04c3b2e7dea2295bdbe3239eb82ec03ada0Timo Sirainen
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 if (fd < 0) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen i_error("open(%s) failed: %m", temp_path);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen return -1;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen }
b650f04c3b2e7dea2295bdbe3239eb82ec03ada0Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen ctx = i_new(struct squat_uidlist_rebuild_context, 1);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen ctx->uidlist = build_ctx->uidlist;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen ctx->build_ctx = build_ctx;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen ctx->fd = fd;
b650f04c3b2e7dea2295bdbe3239eb82ec03ada0Timo Sirainen ctx->output = o_stream_create_fd(ctx->fd, 0, FALSE);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen ctx->next_uid_list_idx = 0x100;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen o_stream_cork(ctx->output);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen memset(&hdr, 0, sizeof(hdr));
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen o_stream_send(ctx->output, &hdr, sizeof(hdr));
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen ctx->cur_block_start_offset = ctx->output->offset;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen i_array_init(&ctx->new_block_offsets,
b650f04c3b2e7dea2295bdbe3239eb82ec03ada0Timo Sirainen build_ctx->build_hdr.count / UIDLIST_BLOCK_LIST_COUNT);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen i_array_init(&ctx->new_block_end_indexes,
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen build_ctx->build_hdr.count / UIDLIST_BLOCK_LIST_COUNT);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen *ctx_r = ctx;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen return 1;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen}
b650f04c3b2e7dea2295bdbe3239eb82ec03ada0Timo Sirainen
b650f04c3b2e7dea2295bdbe3239eb82ec03ada0Timo Sirainenstatic void
b650f04c3b2e7dea2295bdbe3239eb82ec03ada0Timo Sirainenuidlist_rebuild_flush_block(struct squat_uidlist_rebuild_context *ctx)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen{
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen uint8_t buf[SQUAT_PACK_MAX_SIZE], *bufp;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen uint32_t block_offset, block_end_idx;
e22ec7998afd426c53c658483ce66b6e404e27c6Timo Sirainen unsigned int i;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen ctx->new_count += ctx->list_idx;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen block_offset = ctx->output->offset;
b650f04c3b2e7dea2295bdbe3239eb82ec03ada0Timo Sirainen block_end_idx = ctx->new_count;
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
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 bufp = buf;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen squat_pack_num(&bufp, block_offset - ctx->cur_block_start_offset);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen o_stream_send(ctx->output, buf, bufp - buf);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b650f04c3b2e7dea2295bdbe3239eb82ec03ada0Timo Sirainen /* write the sizes/flags */
b650f04c3b2e7dea2295bdbe3239eb82ec03ada0Timo Sirainen for (i = 0; i < ctx->list_idx; i++) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen bufp = buf;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen squat_pack_num(&bufp, ctx->list_sizes[i]);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen o_stream_send(ctx->output, buf, bufp - buf);
e22ec7998afd426c53c658483ce66b6e404e27c6Timo Sirainen }
e22ec7998afd426c53c658483ce66b6e404e27c6Timo Sirainen ctx->cur_block_start_offset = ctx->output->offset;
e22ec7998afd426c53c658483ce66b6e404e27c6Timo Sirainen}
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainenuint32_t squat_uidlist_rebuild_next(struct squat_uidlist_rebuild_context *ctx,
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen const ARRAY_TYPE(uint32_t) *uids)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen{
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen int ret;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen T_BEGIN {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen ret = uidlist_write_array(ctx->output, array_idx(uids, 0),
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen array_count(uids), 0, 0, FALSE,
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen &ctx->list_sizes[ctx->list_idx]);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen } T_END;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (ret < 0)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen squat_uidlist_set_corrupted(ctx->uidlist, "Broken uidlists");
e22ec7998afd426c53c658483ce66b6e404e27c6Timo Sirainen
b50234708ad651e98a4198e1b910106b279aae32Timo Sirainen if (++ctx->list_idx == UIDLIST_BLOCK_LIST_COUNT) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen uidlist_rebuild_flush_block(ctx);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen ctx->list_idx = 0;
b650f04c3b2e7dea2295bdbe3239eb82ec03ada0Timo Sirainen }
6b4b3e5fe8d9e84f4b1356ee898ca76996a11fe1Timo Sirainen return ctx->next_uid_list_idx++ << 1;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen}
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainenuint32_t squat_uidlist_rebuild_nextu(struct squat_uidlist_rebuild_context *ctx,
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen const ARRAY_TYPE(seq_range) *uids)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen{
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen const struct seq_range *range;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen ARRAY_TYPE(uint32_t) tmp_uids;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen uint32_t seq, uid1, ret;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen unsigned int i, count;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
6b4b3e5fe8d9e84f4b1356ee898ca76996a11fe1Timo Sirainen range = array_get(uids, &count);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (count == 0)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen return 0;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (range[count-1].seq2 < 8) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen /* we can use a singleton bitmask */
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen ret = 0;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen for (i = 0; i < count; i++) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen for (seq = range[i].seq1; seq <= range[i].seq2; seq++)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen ret |= 1 << (seq+1);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen }
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen return ret;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen }
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (count == 1 && range[0].seq1 == range[0].seq2) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen /* single UID */
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen return (range[0].seq1 << 1) | 1;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen }
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen /* convert seq range to our internal representation and use the
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen normal _rebuild_next() to write it */
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen i_array_init(&tmp_uids, 128);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen for (i = 0; i < count; i++) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (range[i].seq1 == range[i].seq2)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen array_append(&tmp_uids, &range[i].seq1, 1);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen else {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen uid1 = range[i].seq1 | UID_LIST_MASK_RANGE;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen array_append(&tmp_uids, &uid1, 1);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen array_append(&tmp_uids, &range[i].seq2, 1);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen }
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen }
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen ret = squat_uidlist_rebuild_next(ctx, &tmp_uids);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen array_free(&tmp_uids);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen return ret;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen}
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainenint squat_uidlist_rebuild_finish(struct squat_uidlist_rebuild_context *ctx,
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen bool cancel)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen{
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen const char *temp_path;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen int ret = 1;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (ctx->list_idx != 0)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen uidlist_rebuild_flush_block(ctx);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (cancel || ctx->uidlist->corrupted)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen ret = 0;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen temp_path = t_strconcat(ctx->uidlist->path, ".tmp", NULL);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (ret > 0) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen ctx->build_ctx->build_hdr.indexid =
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen ctx->uidlist->trie->hdr.indexid;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen ctx->build_ctx->build_hdr.count = ctx->new_count;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen ctx->build_ctx->build_hdr.link_count = 0;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen uidlist_write_block_list_and_header(ctx->build_ctx, ctx->output,
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen &ctx->new_block_offsets,
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen &ctx->new_block_end_indexes,
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen FALSE);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen o_stream_seek(ctx->output, 0);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen o_stream_send(ctx->output, &ctx->build_ctx->build_hdr,
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen sizeof(ctx->build_ctx->build_hdr));
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen o_stream_seek(ctx->output,
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen ctx->build_ctx->build_hdr.used_file_size);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen o_stream_flush(ctx->output);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (ctx->uidlist->corrupted)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen ret = -1;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen else if (ctx->output->last_failed_errno != 0) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen errno = ctx->output->last_failed_errno;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen i_error("write() to %s failed: %m", temp_path);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen ret = -1;
} else if (rename(temp_path, ctx->uidlist->path) < 0) {
i_error("rename(%s, %s) failed: %m",
temp_path, ctx->uidlist->path);
ret = -1;
}
ctx->build_ctx->need_reopen = TRUE;
}
o_stream_unref(&ctx->output);
if (close(ctx->fd) < 0)
i_error("close(%s) failed: %m", temp_path);
if (ret <= 0) {
if (unlink(temp_path) < 0)
i_error("unlink(%s) failed: %m", temp_path);
}
array_free(&ctx->new_block_offsets);
array_free(&ctx->new_block_end_indexes);
i_free(ctx);
return ret < 0 ? -1 : 0;
}
static void
uidlist_flush(struct squat_uidlist_build_context *ctx,
struct uidlist_list *list, uint32_t uid)
{
uint32_t size, offset = ctx->output->offset;
ctx->build_hdr.link_count++;
if (uidlist_write(ctx->output, list, TRUE, &size) < 0)
squat_uidlist_set_corrupted(ctx->uidlist, "Broken uidlists");
list->uid_count = 2;
list->uid_begins_with_pointer = TRUE;
list->uid_list[0] = offset;
list->uid_list[1] = uid;
}
static struct uidlist_list *
uidlist_add_new(struct squat_uidlist_build_context *ctx, unsigned int count,
uint32_t *uid_list_idx_r)
{
struct uidlist_list *list;
i_assert(array_count(&ctx->lists) +
ctx->list_start_idx == ctx->build_hdr.count);
*uid_list_idx_r = (ctx->build_hdr.count + 0x100) << 1;
list = array_append_space(&ctx->lists);
ctx->build_hdr.count++;
list->uid_count = count;
return list;
}
uint32_t squat_uidlist_build_add_uid(struct squat_uidlist_build_context *ctx,
uint32_t uid_list_idx, uint32_t uid)
{
struct uidlist_list *list;
unsigned int idx, mask;
uint32_t *p;
if ((uid_list_idx & 1) != 0) {
/* adding second UID */
uint32_t prev_uid = uid_list_idx >> 1;
i_assert(prev_uid != uid);
list = uidlist_add_new(ctx, 2, &uid_list_idx);
list->uid_list[0] = prev_uid;
if (prev_uid + 1 == uid)
list->uid_list[0] |= UID_LIST_MASK_RANGE;
list->uid_list[1] = uid;
return uid_list_idx;
} else if (uid_list_idx < (0x100 << 1)) {
uint32_t old_list_idx;
if (uid < 8) {
/* UID lists containing only UIDs 0-7 are saved as
uidlist values 2..511. think of it as a bitmask. */
uid_list_idx |= 1 << (uid + 1);
i_assert((uid_list_idx & 1) == 0);
return uid_list_idx;
}
if (uid_list_idx == 0) {
/* first UID */
return (uid << 1) | 1;
}
/* create a new list */
old_list_idx = uid_list_idx >> 1;
list = uidlist_add_new(ctx, 1, &uid_list_idx);
/* add the first UID ourself */
idx = 0;
i_assert((old_list_idx & 0xff) != 0);
for (mask = 1; mask <= 128; mask <<= 1, idx++) {
if ((old_list_idx & mask) != 0) {
list->uid_list[0] = idx;
idx++; mask <<= 1;
break;
}
}
for (; mask <= 128; mask <<= 1, idx++) {
if ((old_list_idx & mask) != 0) {
squat_uidlist_build_add_uid(ctx,
uid_list_idx, idx);
}
}
}
/* add to existing list */
idx = (uid_list_idx >> 1) - 0x100;
if (idx < ctx->list_start_idx) {
list = uidlist_add_new(ctx, 2, &uid_list_idx);
list->uid_list[0] = UID_LIST_POINTER_MASK_LIST_IDX | idx;
list->uid_list[1] = uid;
list->uid_begins_with_pointer = TRUE;
ctx->build_hdr.link_count++;
return uid_list_idx;
}
idx -= ctx->list_start_idx;
if (idx >= array_count(&ctx->lists)) {
squat_uidlist_set_corrupted(ctx->uidlist,
"missing/broken uidlist");
return 0;
}
list = array_idx_modifiable(&ctx->lists, idx);
i_assert(list->uid_count > 0);
p = &list->uid_list[list->uid_count-1];
i_assert(uid != *p || ctx->uidlist->corrupted ||
(list->uid_count == 1 && list->uid_begins_with_pointer));
if (uid == *p + 1 &&
(list->uid_count > 1 || !list->uid_begins_with_pointer)) {
/* use a range */
if (list->uid_count > 1 && (p[-1] & UID_LIST_MASK_RANGE) != 0 &&
(list->uid_count > 2 || !list->uid_begins_with_pointer)) {
/* increase the existing range */
*p += 1;
return uid_list_idx;
}
if (list->uid_count == UIDLIST_LIST_SIZE) {
uidlist_flush(ctx, list, uid);
return uid_list_idx;
}
/* create a new range */
*p |= UID_LIST_MASK_RANGE;
}
if (list->uid_count == UIDLIST_LIST_SIZE) {
uidlist_flush(ctx, list, uid);
return uid_list_idx;
}
p++;
list->uid_count++;
*p = uid;
return uid_list_idx;
}
static void uidlist_array_append(ARRAY_TYPE(uint32_t) *uids, uint32_t uid)
{
uint32_t *uidlist;
unsigned int count;
uidlist = array_get_modifiable(uids, &count);
if (count == 0) {
array_append(uids, &uid, 1);
return;
}
if (uidlist[count-1] + 1 == uid) {
if (count > 1 && (uidlist[count-2] &
UID_LIST_MASK_RANGE) != 0) {
uidlist[count-1]++;
return;
}
uidlist[count-1] |= UID_LIST_MASK_RANGE;
}
array_append(uids, &uid, 1);
}
static void uidlist_array_append_range(ARRAY_TYPE(uint32_t) *uids,
uint32_t uid1, uint32_t uid2)
{
uint32_t *uidlist;
unsigned int count;
i_assert(uid1 < uid2);
uidlist = array_get_modifiable(uids, &count);
if (count == 0) {
uid1 |= UID_LIST_MASK_RANGE;
array_append(uids, &uid1, 1);
array_append(uids, &uid2, 1);
return;
}
if (uidlist[count-1] + 1 == uid1) {
if (count > 1 && (uidlist[count-2] &
UID_LIST_MASK_RANGE) != 0) {
uidlist[count-1] = uid2;
return;
}
uidlist[count-1] |= UID_LIST_MASK_RANGE;
} else {
uid1 |= UID_LIST_MASK_RANGE;
array_append(uids, &uid1, 1);
}
array_append(uids, &uid2, 1);
}
static int
squat_uidlist_get_at_offset(struct squat_uidlist *uidlist, uoff_t offset,
uint32_t num, ARRAY_TYPE(uint32_t) *uids)
{
const uint32_t *uid_list;
const uint8_t *p, *end;
uint32_t size, base_uid, next_uid, flags, prev;
uoff_t uidlist_data_offset;
unsigned int i, j, count;
if (num != 0)
uidlist_data_offset = offset;
else {
/* not given, read it */
if (uidlist_file_cache_read(uidlist, offset,
SQUAT_PACK_MAX_SIZE) < 0)
return -1;
p = CONST_PTR_OFFSET(uidlist->data, offset);
end = CONST_PTR_OFFSET(uidlist->data, uidlist->data_size);
num = squat_unpack_num(&p, end);
uidlist_data_offset = p - (const uint8_t *)uidlist->data;
}
size = num >> 2;
if (uidlist_file_cache_read(uidlist, uidlist_data_offset, size) < 0)
return -1;
if (uidlist_data_offset + size > uidlist->data_size) {
squat_uidlist_set_corrupted(uidlist,
"size points outside file");
return -1;
}
p = CONST_PTR_OFFSET(uidlist->data, uidlist_data_offset);
end = p + size;
flags = num;
if ((flags & UIDLIST_PACKED_FLAG_BEGINS_WITH_POINTER) != 0) {
/* link to the file */
prev = squat_unpack_num(&p, end);
if ((prev & 1) != 0) {
/* pointer to uidlist */
prev = ((prev >> 1) + 0x100) << 1;
if (squat_uidlist_get(uidlist, prev, uids) < 0)
return -1;
} else {
prev = offset - (prev >> 1);
if (squat_uidlist_get_at_offset(uidlist, prev,
0, uids) < 0)
return -1;
}
uid_list = array_get(uids, &count);
next_uid = count == 0 ? 0 : uid_list[count-1] + 1;
} else {
next_uid = 0;
}
num = base_uid = squat_unpack_num(&p, end);
if ((flags & UIDLIST_PACKED_FLAG_BITMASK) == 0)
base_uid >>= 1;
if (base_uid < next_uid) {
squat_uidlist_set_corrupted(uidlist,
"broken continued uidlist");
return -1;
}
if ((flags & UIDLIST_PACKED_FLAG_BITMASK) != 0) {
/* bitmask */
size = end - p;
uidlist_array_append(uids, base_uid++);
for (i = 0; i < size; i++) {
for (j = 0; j < 8; j++, base_uid++) {
if ((p[i] & (1 << j)) != 0)
uidlist_array_append(uids, base_uid);
}
}
} else {
/* range */
for (;;) {
if ((num & 1) == 0) {
uidlist_array_append(uids, base_uid);
} else {
/* range */
uint32_t seq1 = base_uid;
base_uid += squat_unpack_num(&p, end) + 1;
uidlist_array_append_range(uids, seq1,
base_uid);
}
if (p == end)
break;
num = squat_unpack_num(&p, end);
base_uid += (num >> 1) + 1;
}
}
return 0;
}
static int uint32_cmp(const void *key, const void *data)
{
const uint32_t *i1 = key, *i2 = data;
return (int)*i1 - (int)*i2;
}
static int
squat_uidlist_get_offset(struct squat_uidlist *uidlist, uint32_t uid_list_idx,
uint32_t *offset_r, uint32_t *num_r)
{
const uint8_t *p, *end;
unsigned int idx;
uint32_t num, skip_bytes, uidlists_offset;
size_t max_map_size;
if (uidlist->fd == -1) {
squat_uidlist_set_corrupted(uidlist, "no uidlists");
return -1;
}
if (bsearch_insert_pos(&uid_list_idx, uidlist->cur_block_end_indexes,
uidlist->cur_block_count,
sizeof(uint32_t), uint32_cmp, &idx))
idx++;
if (unlikely(idx == uidlist->cur_block_count)) {
squat_uidlist_set_corrupted(uidlist, "uidlist not found");
return -1;
}
if (unlikely(idx > 0 &&
uidlist->cur_block_end_indexes[idx-1] > uid_list_idx)) {
squat_uidlist_set_corrupted(uidlist, "broken block list");
return -1;
}
/* make sure everything is mapped */
uid_list_idx -= idx == 0 ? 0 : uidlist->cur_block_end_indexes[idx-1];
max_map_size = SQUAT_PACK_MAX_SIZE * (1+uid_list_idx);
if (uidlist_file_cache_read(uidlist, uidlist->cur_block_offsets[idx],
max_map_size) < 0)
return -1;
/* find the uidlist inside the block */
p = CONST_PTR_OFFSET(uidlist->data, uidlist->cur_block_offsets[idx]);
end = CONST_PTR_OFFSET(uidlist->data, uidlist->data_size);
uidlists_offset = uidlist->cur_block_offsets[idx] -
squat_unpack_num(&p, end);
for (skip_bytes = 0; uid_list_idx > 0; uid_list_idx--) {
num = squat_unpack_num(&p, end);
skip_bytes += num >> 2;
}
*offset_r = uidlists_offset + skip_bytes;
*num_r = squat_unpack_num(&p, end);
if (unlikely(p == end)) {
squat_uidlist_set_corrupted(uidlist, "broken file");
return -1;
}
if (unlikely(*offset_r > uidlist->mmap_size &&
uidlist->mmap_base != NULL)) {
squat_uidlist_set_corrupted(uidlist, "broken offset");
return -1;
}
return 0;
}
int squat_uidlist_get(struct squat_uidlist *uidlist, uint32_t uid_list_idx,
ARRAY_TYPE(uint32_t) *uids)
{
unsigned int mask;
uint32_t uid, offset, num;
if ((uid_list_idx & 1) != 0) {
/* single UID */
uid = uid_list_idx >> 1;
uidlist_array_append(uids, uid);
return 0;
} else if (uid_list_idx < (0x100 << 1)) {
/* bitmask */
for (uid = 0, mask = 2; mask <= 256; mask <<= 1, uid++) {
if ((uid_list_idx & mask) != 0)
uidlist_array_append(uids, uid);
}
return 0;
}
uid_list_idx = (uid_list_idx >> 1) - 0x100;
if (squat_uidlist_get_offset(uidlist, uid_list_idx, &offset, &num) < 0)
return -1;
return squat_uidlist_get_at_offset(uidlist, offset, num, uids);
}
uint32_t squat_uidlist_singleton_last_uid(uint32_t uid_list_idx)
{
unsigned int idx, mask;
if ((uid_list_idx & 1) != 0) {
/* single UID */
return uid_list_idx >> 1;
} else if (uid_list_idx < (0x100 << 1)) {
/* bitmask */
if (uid_list_idx == 2) {
/* just a quick optimization */
return 0;
}
for (idx = 7, mask = 256; mask > 2; mask >>= 1, idx--) {
if ((uid_list_idx & mask) != 0)
return idx;
}
}
i_unreached();
return 0;
}
int squat_uidlist_get_seqrange(struct squat_uidlist *uidlist,
uint32_t uid_list_idx,
ARRAY_TYPE(seq_range) *seq_range_arr)
{
ARRAY_TYPE(uint32_t) tmp_uid_arr;
struct seq_range range;
const uint32_t *tmp_uids;
unsigned int i, count;
int ret;
i_array_init(&tmp_uid_arr, 128);
ret = squat_uidlist_get(uidlist, uid_list_idx, &tmp_uid_arr);
if (ret == 0) {
tmp_uids = array_get(&tmp_uid_arr, &count);
for (i = 0; i < count; i++) {
if ((tmp_uids[i] & UID_LIST_MASK_RANGE) == 0)
range.seq1 = range.seq2 = tmp_uids[i];
else {
range.seq1 = tmp_uids[i] & ~UID_LIST_MASK_RANGE;
range.seq2 = tmp_uids[++i];
}
array_append(seq_range_arr, &range, 1);
}
}
array_free(&tmp_uid_arr);
return ret;
}
int squat_uidlist_filter(struct squat_uidlist *uidlist, uint32_t uid_list_idx,
ARRAY_TYPE(seq_range) *uids)
{
const struct seq_range *parent_range;
ARRAY_TYPE(seq_range) dest_uids;
ARRAY_TYPE(uint32_t) relative_uids;
const uint32_t *rel_range;
unsigned int i, rel_count, parent_idx, parent_count, diff, parent_uid;
uint32_t prev_seq, seq1, seq2;
int ret = 0;
parent_range = array_get(uids, &parent_count);
if (parent_count == 0)
return 0;
i_array_init(&relative_uids, 128);
i_array_init(&dest_uids, 128);
squat_uidlist_get(uidlist, uid_list_idx, &relative_uids);
parent_idx = 0;
rel_range = array_get(&relative_uids, &rel_count);
prev_seq = 0; parent_uid = parent_range[0].seq1;
for (i = 0; i < rel_count; i++) {
if (unlikely(parent_uid == (uint32_t)-1)) {
i_error("broken UID ranges");
ret = -1;
break;
}
if ((rel_range[i] & UID_LIST_MASK_RANGE) == 0)
seq1 = seq2 = rel_range[i];
else {
seq1 = (rel_range[i] & ~UID_LIST_MASK_RANGE);
seq2 = rel_range[++i];
}
i_assert(seq1 >= prev_seq);
diff = seq1 - prev_seq;
while (diff > 0) {
if (unlikely(parent_uid == (uint32_t)-1)) {
i_error("broken UID ranges");
ret = -1;
break;
}
for (; parent_idx < parent_count; parent_idx++) {
if (parent_range[parent_idx].seq2 <= parent_uid)
continue;
if (parent_uid < parent_range[parent_idx].seq1)
parent_uid = parent_range[parent_idx].seq1;
else
parent_uid++;
break;
}
diff--;
}
diff = seq2 - seq1 + 1;
while (diff > 0) {
if (unlikely(parent_uid == (uint32_t)-1)) {
i_error("broken UID ranges");
ret = -1;
break;
}
seq_range_array_add(&dest_uids, 0, parent_uid);
for (; parent_idx < parent_count; parent_idx++) {
if (parent_range[parent_idx].seq2 <= parent_uid)
continue;
if (parent_uid < parent_range[parent_idx].seq1)
parent_uid = parent_range[parent_idx].seq1;
else
parent_uid++;
break;
}
diff--;
}
prev_seq = seq2 + 1;
}
buffer_set_used_size(uids->arr.buffer, 0);
array_append_array(uids, &dest_uids);
array_free(&relative_uids);
array_free(&dest_uids);
return 0;
}
size_t squat_uidlist_mem_used(struct squat_uidlist *uidlist,
unsigned int *count_r)
{
*count_r = uidlist->hdr.count;
return uidlist->max_size;
}