mail-cache-lookup.c revision 58febed28f2af78b2d8a281c851d9b67160c4bd3
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen/* Copyright (C) 2003-2004 Timo Sirainen */
a40d26f83af808a0ea1e212c001d682a96d870b0Timo Sirainenmail_cache_get_record(struct mail_cache *cache, uint32_t offset)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (offset + sizeof(*cache_rec) > cache->mmap_length) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mail_cache_set_corrupted(cache, "record points outside file");
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mail_cache_set_corrupted(cache, "invalid record size");
a40d26f83af808a0ea1e212c001d682a96d870b0Timo Sirainen if (mail_cache_map(cache, offset, cache_rec->size) < 0)
785b1ca149341b70bf2cb8cc3049f1c4c1070b52Timo Sirainen offset + cache_rec->size > cache->mmap_length) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mail_cache_set_corrupted(cache, "record points outside file");
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainenstatic int mail_cache_lookup_offset(struct mail_cache_view *view, uint32_t seq,
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen for (i = 0; i < 2; i++) {
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (mail_index_lookup_full(view->view, seq, &map, &rec) < 0)
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen if (map->hdr->cache_file_seq == view->cache->hdr->file_seq) {
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen if ((ret = mail_cache_reopen(view->cache)) <= 0)
2112c190034c937b4b1613c3689d8239adb6c310Timo Sirainenmail_cache_foreach_rec(struct mail_cache_view *view, uint32_t *offset,
ca316aeb7648d3f1bcf45231f73ddeb1b67a6961Timo Sirainen mail_cache_foreach_callback_t *callback, void *context)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen unsigned int field;
2112c190034c937b4b1613c3689d8239adb6c310Timo Sirainen cache_rec = mail_cache_get_record(view->cache, *offset);
ca316aeb7648d3f1bcf45231f73ddeb1b67a6961Timo Sirainen if (max_size < sizeof(*cache_rec) + sizeof(uint32_t)*2) {
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen mail_cache_set_corrupted(cache, "record has invalid size");
ca316aeb7648d3f1bcf45231f73ddeb1b67a6961Timo Sirainen for (pos = sizeof(*cache_rec); pos < max_size; ) {
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen *((const uint32_t *)CONST_PTR_OFFSET(cache_rec, pos));
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen /* new field, have to re-read fields header to figure
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen out it's size */
68aa521f6fc7a40480a56a7b3d61c7dda19061f3Timo Sirainen "field index too large (%u >= %u)",
2112c190034c937b4b1613c3689d8239adb6c310Timo Sirainen /* field reading might have re-mmaped the file and
2112c190034c937b4b1613c3689d8239adb6c310Timo Sirainen caused cache_rec to break. need to get it again. */
2112c190034c937b4b1613c3689d8239adb6c310Timo Sirainen cache_rec = mail_cache_get_record(view->cache, *offset);
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen data_size = cache->fields[field].field.field_size;
785b1ca149341b70bf2cb8cc3049f1c4c1070b52Timo Sirainen if (data_size > cache_rec->size || next_pos > cache_rec->size) {
785b1ca149341b70bf2cb8cc3049f1c4c1070b52Timo Sirainen "record continues outside it's allocated size");
4edf90751f075cc6ab3d6f53fc78b656efa80922Timo Sirainen ret = callback(view, field, CONST_PTR_OFFSET(cache_rec, pos),
785b1ca149341b70bf2cb8cc3049f1c4c1070b52Timo Sirainenstatic int buffer_find_offset(const buffer_t *buffer, uint32_t offset)
785b1ca149341b70bf2cb8cc3049f1c4c1070b52Timo Sirainen for (i = 0; i < size; i++) {
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainenint mail_cache_foreach(struct mail_cache_view *view, uint32_t seq,
ca316aeb7648d3f1bcf45231f73ddeb1b67a6961Timo Sirainen mail_cache_foreach_callback_t *callback, void *context)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen if ((ret = mail_cache_lookup_offset(view, seq, &offset)) <= 0)
58febed28f2af78b2d8a281c851d9b67160c4bd3Timo Sirainen if (buffer_find_offset(view->offsets_buf, offset)) {
785b1ca149341b70bf2cb8cc3049f1c4c1070b52Timo Sirainen "record list is circular");
58febed28f2af78b2d8a281c851d9b67160c4bd3Timo Sirainen buffer_append(view->offsets_buf, &offset, sizeof(offset));
785b1ca149341b70bf2cb8cc3049f1c4c1070b52Timo Sirainen if (ret > 0 && view->trans_seq1 <= seq && view->trans_seq2 >= seq &&
ca316aeb7648d3f1bcf45231f73ddeb1b67a6961Timo Sirainen mail_cache_transaction_lookup(view->transaction, seq, &offset)) {
58febed28f2af78b2d8a281c851d9b67160c4bd3Timo Sirainen if (buffer_find_offset(view->offsets_buf, offset)) {
785b1ca149341b70bf2cb8cc3049f1c4c1070b52Timo Sirainen "record list is circular");
4edf90751f075cc6ab3d6f53fc78b656efa80922Timo Sirainenmail_cache_seq_callback(struct mail_cache_view *view, uint32_t field,
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainenstatic int mail_cache_seq(struct mail_cache_view *view, uint32_t seq)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen /* wrapped, we'll have to clear the buffer */
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen memset(buffer_get_modifyable_data(view->cached_exists_buf,
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen ret = mail_cache_foreach(view, seq, mail_cache_seq_callback, NULL);
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainenint mail_cache_field_exists(struct mail_cache_view *view, uint32_t seq,
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen unsigned int field)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen file_field = view->cache->field_file_map[field];
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen data = buffer_get_data(view->cached_exists_buf, &size);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainenmail_cache_field_get_decision(struct mail_cache *cache, unsigned int field)
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainenmail_cache_lookup_callback(struct mail_cache_view *view __attr_unused__,
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen struct mail_cache_lookup_context *ctx = context;
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen buffer_append(ctx->dest_buf, data, data_size);
dd4b5f14b71b01a84af942e720a2d6e5f15ee1a7Timo Sirainenmail_cache_lookup_bitmask_callback(struct mail_cache_view *view __attr_unused__,
dd4b5f14b71b01a84af942e720a2d6e5f15ee1a7Timo Sirainen struct mail_cache_lookup_context *ctx = context;
dd4b5f14b71b01a84af942e720a2d6e5f15ee1a7Timo Sirainen unsigned char *dest;
dd4b5f14b71b01a84af942e720a2d6e5f15ee1a7Timo Sirainen /* merge all bits */
dd4b5f14b71b01a84af942e720a2d6e5f15ee1a7Timo Sirainen dest = buffer_get_space_unsafe(ctx->dest_buf, 0, data_size);
dd4b5f14b71b01a84af942e720a2d6e5f15ee1a7Timo Sirainen for (i = 0; i < data_size; i++)
1171f0abf442638bac1827bb24a0b6b8eb682a82Timo Sirainenint mail_cache_lookup_field(struct mail_cache_view *view, buffer_t *dest_buf,
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen if ((ret = mail_cache_field_exists(view, seq, field)) <= 0)
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen /* should exist. find it. */
dd4b5f14b71b01a84af942e720a2d6e5f15ee1a7Timo Sirainen if (view->cache->fields[field].field.type != MAIL_CACHE_FIELD_BITMASK) {
dd4b5f14b71b01a84af942e720a2d6e5f15ee1a7Timo Sirainen ret = mail_cache_foreach(view, seq, mail_cache_lookup_callback,
dd4b5f14b71b01a84af942e720a2d6e5f15ee1a7Timo Sirainen /* make sure we're cleared first */
dd4b5f14b71b01a84af942e720a2d6e5f15ee1a7Timo Sirainen data_size = view->cache->fields[field].field.field_size;
dd4b5f14b71b01a84af942e720a2d6e5f15ee1a7Timo Sirainen memset(buffer_get_space_unsafe(dest_buf, 0, data_size),
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen unsigned int *fields;
4edf90751f075cc6ab3d6f53fc78b656efa80922Timo Sirainenheaders_find_callback(struct mail_cache_view *view, uint32_t field,
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen const void *data, size_t data_size, void *context)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen unsigned int i, lines_count;
4edf90751f075cc6ab3d6f53fc78b656efa80922Timo Sirainen if (field > ctx->max_field || ctx->fields_found[field] != 1) {
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen /* a) don't want it, b) duplicate */
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen /* data = { line_nums[], 0, "headers" } */
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen for (i = 0; data_size >= sizeof(uint32_t); i++) {
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen /* FIXME: this relies on mmap() too heavily */
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen hdr_data_rec = t_new(struct header_lookup_data_rec, 1);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen hdr_data_rec->offset = (const char *)&lines[lines_count+1] -
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen hdr_data_rec->data_size = (uint32_t)data_size;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen for (i = 0; i < lines_count; i++) {
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen buffer_append(ctx->data, &hdr_data, sizeof(hdr_data));
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainenstatic int header_lookup_data_cmp(const void *p1, const void *p2)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen const struct header_lookup_data *d1 = p1, *d2 = p2;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainenint mail_cache_lookup_headers(struct mail_cache_view *view, string_t *dest,
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen /* @UNSAFE */
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen ctx.fields = t_new(unsigned int, fields_count);
65a5fb2343f9870713bfca0b24abb58dcade605eTimo Sirainen buf = buffer_create_dynamic(pool_datastack_create(), 32, (size_t)-1);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen for (i = 0; i < fields_count; i++) {
4edf90751f075cc6ab3d6f53fc78b656efa80922Timo Sirainen if (cache->field_file_map[fields[i]] == (unsigned int)-1) {
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen /* not cached at all */
65a5fb2343f9870713bfca0b24abb58dcade605eTimo Sirainen ctx.fields_found = buffer_get_modifyable_data(buf, NULL);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen ctx.data = buffer_create_dynamic(pool_datastack_create(),
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen /* we need to return them in sorted order. create array:
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen { line number -> cache file offset } */
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen ret = mail_cache_foreach(view, seq, headers_find_callback, &ctx);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen /* check that all fields were found */
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen data = buffer_get_modifyable_data(ctx.data, &size);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen qsort(data, size, sizeof(*data), header_lookup_data_cmp);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen /* then start filling dest buffer from the headers */
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen for (i = 0; i < size; i++) {
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen if (*p == '\n' &&
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen (p+1 == end || (p[1] != ' ' && p[1] != '\t'))) {