doveadm-dump-index.c revision 0374f48baf19b33bff02f309f9bbe52632972eba
c25356d5978632df6203437e1953bcb29e0c736fTimo Sirainen/* Copyright (c) 2007-2011 Dovecot authors, see the included COPYING file */
c25356d5978632df6203437e1953bcb29e0c736fTimo Sirainen
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen#include "lib.h"
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen#include "array.h"
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen#include "str.h"
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen#include "hex-binary.h"
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen#include "file-lock.h"
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen#include "message-parser.h"
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen#include "message-part-serialize.h"
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen#include "mail-index-private.h"
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen#include "mail-cache-private.h"
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen#include "mail-cache-private.h"
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen#include "mail-index-modseq.h"
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen#include "doveadm-dump.h"
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen
4ee00532a265bdfb38539d811fcd12d51210ac35Timo Sirainen#include <stdio.h>
4ee00532a265bdfb38539d811fcd12d51210ac35Timo Sirainen#include <stdlib.h>
5be5d875996999585de785ac33f96ff1569f1a0eTimo Sirainen#include <time.h>
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainenstruct index_vsize_header {
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen uint64_t vsize;
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen uint32_t highest_uid;
3fe44a0df5a0bdd80c495f79cbf0e384441d6fccTimo Sirainen uint32_t message_count;
4ee00532a265bdfb38539d811fcd12d51210ac35Timo Sirainen};
3fe44a0df5a0bdd80c495f79cbf0e384441d6fccTimo Sirainenstruct maildir_index_header {
3fe44a0df5a0bdd80c495f79cbf0e384441d6fccTimo Sirainen uint32_t new_check_time, new_mtime, new_mtime_nsecs;
62300a38f91227b9de043a9a8ec1d4f1978e1138Timo Sirainen uint32_t cur_check_time, cur_mtime, cur_mtime_nsecs;
b87436ebb957a9eb182be72ba00e2c8eae59a2e4Timo Sirainen uint32_t uidlist_mtime, uidlist_mtime_nsecs, uidlist_size;
fc84f8af4794f4bb6caf6e5ec3fb1f8cebd0462aTimo Sirainen};
b8a4aab1f117f6760184ad50b1af41ba810b51f9Timo Sirainenstruct mbox_index_header {
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen uint64_t sync_size;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen uint32_t sync_mtime;
12dc81583d1958cb301a617e19fbd40e8d376397Timo Sirainen uint8_t dirty_flag;
81e4bda7d481c57cd049a0a68daab733b1ca9c44Timo Sirainen uint8_t unused[3];
12dc81583d1958cb301a617e19fbd40e8d376397Timo Sirainen uint8_t mailbox_guid[16];
12dc81583d1958cb301a617e19fbd40e8d376397Timo Sirainen};
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainenstruct sdbox_index_header {
d7babe048f9ae1afa5357973b8de8c929753a216Timo Sirainen uint32_t rebuild_count;
2b682d8d3661800f16aceaa45fa4de9b6b140a59Timo Sirainen guid_128_t mailbox_guid;
2b682d8d3661800f16aceaa45fa4de9b6b140a59Timo Sirainen};
2b682d8d3661800f16aceaa45fa4de9b6b140a59Timo Sirainenstruct mdbox_index_header {
12dc81583d1958cb301a617e19fbd40e8d376397Timo Sirainen uint32_t map_uid_validity;
12dc81583d1958cb301a617e19fbd40e8d376397Timo Sirainen guid_128_t mailbox_guid;
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen};
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainenstruct mdbox_mail_index_record {
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen uint32_t map_uid;
ad4f1b0666975c57dd2d8d3492b223ec814791cdTimo Sirainen uint32_t save_date;
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen};
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainenstruct fts_index_header {
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen uint32_t last_indexed_uid;
9b61a6db87c026656f8d2ae214e4486b98a069c0Timo Sirainen uint32_t settings_checksum;
9b61a6db87c026656f8d2ae214e4486b98a069c0Timo Sirainen uint32_t unused;
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen};
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainenstruct virtual_mail_index_header {
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen uint32_t change_counter;
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen uint32_t mailbox_count;
12dc81583d1958cb301a617e19fbd40e8d376397Timo Sirainen uint32_t highest_mailbox_id;
cb931f84e3ec8e3deda253a1c0ae0409023de096Timo Sirainen uint32_t search_args_crc32;
12dc81583d1958cb301a617e19fbd40e8d376397Timo Sirainen};
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainenstruct virtual_mail_index_mailbox_record {
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen uint32_t id;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen uint32_t name_len;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen uint32_t uid_validity;
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen uint32_t next_uid;
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen uint64_t highest_modseq;
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen};
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainenstruct virtual_mail_index_record {
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen uint32_t mailbox_id;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen uint32_t real_uid;
6d6bbe8787354bbb69d0c03187adfe0f497d70b8Timo Sirainen};
048e40f9364fa68482bc276dd4a5d595a3d742e9Timo Sirainen
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainenstruct mdbox_mail_index_map_record {
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen uint32_t file_id;
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen uint32_t offset;
3fe44a0df5a0bdd80c495f79cbf0e384441d6fccTimo Sirainen uint32_t size;
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen};
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainenstatic void dump_hdr(struct mail_index *index)
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen{
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen const struct mail_index_header *hdr = &index->map->hdr;
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen unsigned int i;
73583cff4f0ca9ee87204256ca1994adf17cb94cTimo Sirainen
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen printf("version .................. = %u.%u\n", hdr->major_version, hdr->minor_version);
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen printf("base header size ......... = %u\n", hdr->base_header_size);
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen printf("header size .............. = %u\n", hdr->header_size);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen printf("record size .............. = %u\n", hdr->record_size);
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen printf("compat flags ............. = %u\n", hdr->compat_flags);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen printf("index id ................. = %u (%s)\n", hdr->indexid, unixdate2str(hdr->indexid));
4ee00532a265bdfb38539d811fcd12d51210ac35Timo Sirainen printf("flags .................... = %u\n", hdr->flags);
4ee00532a265bdfb38539d811fcd12d51210ac35Timo Sirainen printf("uid validity ............. = %u (%s)\n", hdr->uid_validity, unixdate2str(hdr->uid_validity));
2521fd0986302cdabc8b0711eef63ac188f32cd6Timo Sirainen printf("next uid ................. = %u\n", hdr->next_uid);
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen printf("messages count ........... = %u\n", hdr->messages_count);
bc7a4cf2c06702ebaedba9a7c15ce657d5856f63Timo Sirainen printf("seen messages count ...... = %u\n", hdr->seen_messages_count);
bc7a4cf2c06702ebaedba9a7c15ce657d5856f63Timo Sirainen printf("deleted messages count ... = %u\n", hdr->deleted_messages_count);
bc7a4cf2c06702ebaedba9a7c15ce657d5856f63Timo Sirainen printf("first recent uid ......... = %u\n", hdr->first_recent_uid);
ad0fe438255666726723a93f3112df6e103028afTimo Sirainen printf("first unseen uid lowwater = %u\n", hdr->first_unseen_uid_lowwater);
bc7a4cf2c06702ebaedba9a7c15ce657d5856f63Timo Sirainen printf("first deleted uid lowwater = %u\n", hdr->first_deleted_uid_lowwater);
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen printf("log file seq ............. = %u\n", hdr->log_file_seq);
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen if (hdr->minor_version == 0) {
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen printf("log file int offset ...... = %u\n", hdr->log_file_tail_offset);
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen printf("log file ext offset ...... = %u\n", hdr->log_file_head_offset);
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen } else {
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen printf("log file tail offset ..... = %u\n", hdr->log_file_tail_offset);
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen printf("log file head offset ..... = %u\n", hdr->log_file_head_offset);
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen }
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen printf("day stamp ................ = %u (%s)\n", hdr->day_stamp, unixdate2str(hdr->day_stamp));
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen for (i = 0; i < N_ELEMENTS(hdr->day_first_uid); i++)
2521fd0986302cdabc8b0711eef63ac188f32cd6Timo Sirainen printf("day first uid[%u] ......... = %u\n", i, hdr->day_first_uid[i]);
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen}
2d8b23805db6f06b8b38174fb6e135386694f429Timo Sirainen
2d8b23805db6f06b8b38174fb6e135386694f429Timo Sirainenstatic void dump_extension_header(struct mail_index *index,
2d8b23805db6f06b8b38174fb6e135386694f429Timo Sirainen const struct mail_index_ext *ext)
766115d2b2e6dbcf59f90d3b3866851cf6f740feTimo Sirainen{
766115d2b2e6dbcf59f90d3b3866851cf6f740feTimo Sirainen const void *data;
766115d2b2e6dbcf59f90d3b3866851cf6f740feTimo Sirainen
766115d2b2e6dbcf59f90d3b3866851cf6f740feTimo Sirainen if (strcmp(ext->name, MAIL_INDEX_EXT_KEYWORDS) == 0)
2d8b23805db6f06b8b38174fb6e135386694f429Timo Sirainen return;
2d8b23805db6f06b8b38174fb6e135386694f429Timo Sirainen
b1678954f83e1059b981e2def52a70054fa71399Timo Sirainen data = CONST_PTR_OFFSET(index->map->hdr_base, ext->hdr_offset);
b1678954f83e1059b981e2def52a70054fa71399Timo Sirainen if (strcmp(ext->name, "hdr-vsize") == 0) {
b1678954f83e1059b981e2def52a70054fa71399Timo Sirainen const struct index_vsize_header *hdr = data;
b1678954f83e1059b981e2def52a70054fa71399Timo Sirainen
0e5819a061034f1636b124c03a89f67d37c852b1Timo Sirainen printf("header\n");
0e5819a061034f1636b124c03a89f67d37c852b1Timo Sirainen printf(" - highest uid . = %u\n", hdr->highest_uid);
0e5819a061034f1636b124c03a89f67d37c852b1Timo Sirainen printf(" - message count = %u\n", hdr->message_count);
b1678954f83e1059b981e2def52a70054fa71399Timo Sirainen printf(" - vsize ....... = %llu\n", (unsigned long long)hdr->vsize);
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen } else if (strcmp(ext->name, "maildir") == 0) {
4ee00532a265bdfb38539d811fcd12d51210ac35Timo Sirainen const struct maildir_index_header *hdr = data;
d5d23d5ff8b7a06d2ead489ddcf55ee8fb5ca7b6Timo Sirainen
d5d23d5ff8b7a06d2ead489ddcf55ee8fb5ca7b6Timo Sirainen printf("header\n");
d5d23d5ff8b7a06d2ead489ddcf55ee8fb5ca7b6Timo Sirainen printf(" - new_check_time .... = %s\n", unixdate2str(hdr->new_check_time));
d19d3aa4eafa34b48b7d7d311c9db31e1898576aTimo Sirainen printf(" - new_mtime ......... = %s\n", unixdate2str(hdr->new_mtime));
d19d3aa4eafa34b48b7d7d311c9db31e1898576aTimo Sirainen printf(" - new_mtime_nsecs ... = %u\n", hdr->new_mtime_nsecs);
8eb223b84389a7b75a39d46484f5166d221305ebTimo Sirainen printf(" - cur_check_time .... = %s\n", unixdate2str(hdr->cur_check_time));
8eb223b84389a7b75a39d46484f5166d221305ebTimo Sirainen printf(" - cur_mtime ......... = %s\n", unixdate2str(hdr->cur_mtime));
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen printf(" - cur_mtime_nsecs.... = %u\n", hdr->cur_mtime_nsecs);
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen printf(" - uidlist_mtime ..... = %s\n", unixdate2str(hdr->uidlist_mtime));
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen printf(" - uidlist_mtime_nsecs = %u\n", hdr->uidlist_mtime_nsecs);
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen printf(" - uidlist_size ...... = %u\n", hdr->uidlist_size);
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen } else if (strcmp(ext->name, "mbox") == 0) {
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen const struct mbox_index_header *hdr = data;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen printf("header\n");
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen printf(" - sync_mtime . = %s\n", unixdate2str(hdr->sync_mtime));
30ad2b0309119501efad06c72ec9b1561b90d4afTimo Sirainen printf(" - sync_size .. = %llu\n",
bc7a4cf2c06702ebaedba9a7c15ce657d5856f63Timo Sirainen (unsigned long long)hdr->sync_size);
bc7a4cf2c06702ebaedba9a7c15ce657d5856f63Timo Sirainen printf(" - dirty_flag . = %d\n", hdr->dirty_flag);
bc7a4cf2c06702ebaedba9a7c15ce657d5856f63Timo Sirainen printf(" - mailbox_guid = %s\n",
bc7a4cf2c06702ebaedba9a7c15ce657d5856f63Timo Sirainen guid_128_to_string(hdr->mailbox_guid));
bc7a4cf2c06702ebaedba9a7c15ce657d5856f63Timo Sirainen } else if (strcmp(ext->name, "mdbox-hdr") == 0) {
bc7a4cf2c06702ebaedba9a7c15ce657d5856f63Timo Sirainen const struct mdbox_index_header *hdr = data;
bc7a4cf2c06702ebaedba9a7c15ce657d5856f63Timo Sirainen
b863b7e3fccf75f90f613b875f02fd1781e14e5eTimo Sirainen printf("header\n");
b863b7e3fccf75f90f613b875f02fd1781e14e5eTimo Sirainen printf(" - map_uid_validity .. = %u\n", hdr->map_uid_validity);
b863b7e3fccf75f90f613b875f02fd1781e14e5eTimo Sirainen printf(" - mailbox_guid ...... = %s\n",
269370f66e320a071700e33d9f2584eb46d96a90Timo Sirainen guid_128_to_string(hdr->mailbox_guid));
fbdd091ef000e3ec4db34c054736c91ef9bc48ceTimo Sirainen } else if (strcmp(ext->name, "dbox-hdr") == 0) {
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen const struct sdbox_index_header *hdr = data;
6800c6607013d4fdef5a4f764bae407301c6cce8Timo Sirainen
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen printf("header\n");
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen printf(" - rebuild_count . = %u\n", hdr->rebuild_count);
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen printf(" - mailbox_guid .. = %s\n",
aaebcf0da12df7216be69961204fa64ec24c54b9Timo Sirainen guid_128_to_string(hdr->mailbox_guid));
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen } else if (strcmp(ext->name, "modseq") == 0) {
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen const struct mail_index_modseq_header *hdr = data;
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen printf("header\n");
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen printf(" - highest_modseq = %llu\n",
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen (unsigned long long)hdr->highest_modseq);
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen printf(" - log_seq ...... = %u\n", hdr->log_seq);
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen printf(" - log_offset ... = %u\n", hdr->log_offset);
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen } else if (strcmp(ext->name, "fts") == 0) {
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen const struct fts_index_header *hdr = data;
2b682d8d3661800f16aceaa45fa4de9b6b140a59Timo Sirainen
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen printf("header\n");
2b682d8d3661800f16aceaa45fa4de9b6b140a59Timo Sirainen printf(" - last_indexed_uid ..... = %u\n",
d761c26f2bbf514e0fc0c6ed9bc52627a4179eabTimo Sirainen hdr->last_indexed_uid);
d761c26f2bbf514e0fc0c6ed9bc52627a4179eabTimo Sirainen printf(" - settings_checksum .... = %u\n",
d761c26f2bbf514e0fc0c6ed9bc52627a4179eabTimo Sirainen hdr->settings_checksum);
2b682d8d3661800f16aceaa45fa4de9b6b140a59Timo Sirainen } else if (strcmp(ext->name, "virtual") == 0) {
62300a38f91227b9de043a9a8ec1d4f1978e1138Timo Sirainen const struct virtual_mail_index_header *hdr = data;
b863b7e3fccf75f90f613b875f02fd1781e14e5eTimo Sirainen const struct virtual_mail_index_mailbox_record *rec;
b863b7e3fccf75f90f613b875f02fd1781e14e5eTimo Sirainen const unsigned char *name;
b863b7e3fccf75f90f613b875f02fd1781e14e5eTimo Sirainen unsigned int i;
b863b7e3fccf75f90f613b875f02fd1781e14e5eTimo Sirainen
b863b7e3fccf75f90f613b875f02fd1781e14e5eTimo Sirainen printf("header\n");
b863b7e3fccf75f90f613b875f02fd1781e14e5eTimo Sirainen printf(" - change_counter ... = %u\n", hdr->change_counter);
b863b7e3fccf75f90f613b875f02fd1781e14e5eTimo Sirainen printf(" - mailbox_count .... = %u\n", hdr->mailbox_count);
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen printf(" - highest_mailbox_id = %u\n", hdr->highest_mailbox_id);
printf(" - search_args_crc32 = %u\n", hdr->search_args_crc32);
rec = CONST_PTR_OFFSET(hdr, sizeof(*hdr));
name = CONST_PTR_OFFSET(rec, sizeof(*rec) * hdr->mailbox_count);
for (i = 0; i < hdr->mailbox_count; i++, rec++) {
printf("mailbox %s:\n", t_strndup(name, rec->name_len));
printf(" - id ........... = %u\n", rec->id);
printf(" - uid_validity . = %u\n", rec->uid_validity);
printf(" - next_uid ..... = %u\n", rec->next_uid);
printf(" - highest_modseq = %llu\n",
(unsigned long long)rec->highest_modseq);
name += rec->name_len;
}
} else {
printf("header ........ = %s\n",
binary_to_hex(data, ext->hdr_size));
}
}
static void dump_extensions(struct mail_index *index)
{
const struct mail_index_ext *extensions;
unsigned int i, count;
if (array_is_created(&index->map->extensions))
extensions = array_get(&index->map->extensions, &count);
else
count = 0;
if (count == 0) {
printf("no extensions\n");
return;
}
for (i = 0; i < count; i++) {
const struct mail_index_ext *ext = &extensions[i];
printf("-- Extension %u --\n", i);
printf("name ........ = %s\n", ext->name);
printf("hdr_size .... = %u\n", ext->hdr_size);
printf("reset_id .... = %u\n", ext->reset_id);
printf("record_offset = %u\n", ext->record_offset);
printf("record_size . = %u\n", ext->record_size);
printf("record_align = %u\n", ext->record_align);
if (ext->hdr_size > 0)
dump_extension_header(index, ext);
}
}
static void dump_keywords(struct mail_index *index)
{
const unsigned int *kw_indexes;
const char *const *keywords;
unsigned int i, count;
printf("-- Keywords --\n");
if (!array_is_created(&index->map->keyword_idx_map))
return;
kw_indexes = array_get(&index->map->keyword_idx_map, &count);
if (count == 0)
return;
keywords = array_idx(&index->keywords, 0);
for (i = 0; i < count; i++)
printf("%3u = %s\n", i, keywords[kw_indexes[i]]);
}
static const char *cache_decision2str(enum mail_cache_decision_type type)
{
const char *str;
switch (type & ~MAIL_CACHE_DECISION_FORCED) {
case MAIL_CACHE_DECISION_NO:
str = "no";
break;
case MAIL_CACHE_DECISION_TEMP:
str = "tmp";
break;
case MAIL_CACHE_DECISION_YES:
str = "yes";
break;
default:
return t_strdup_printf("0x%x", type);
}
if ((type & MAIL_CACHE_DECISION_FORCED) != 0)
str = t_strconcat(str, "!", NULL);
return str;
}
#define CACHE_TYPE_IS_FIXED_SIZE(type) \
((type) == MAIL_CACHE_FIELD_FIXED_SIZE || \
(type) == MAIL_CACHE_FIELD_BITMASK)
static const char *cache_type2str(enum mail_cache_field_type type)
{
switch (type) {
case MAIL_CACHE_FIELD_FIXED_SIZE:
return "fix";
case MAIL_CACHE_FIELD_VARIABLE_SIZE:
return "var";
case MAIL_CACHE_FIELD_STRING:
return "str";
case MAIL_CACHE_FIELD_BITMASK:
return "bit";
case MAIL_CACHE_FIELD_HEADER:
return "hdr";
default:
return t_strdup_printf("0x%x", type);
}
}
static void dump_cache_hdr(struct mail_cache *cache)
{
const struct mail_cache_header *hdr;
const struct mail_cache_field *fields, *field;
unsigned int i, count, cache_idx;
(void)mail_cache_open_and_verify(cache);
if (MAIL_CACHE_IS_UNUSABLE(cache)) {
printf("cache is unusable\n");
return;
}
hdr = cache->hdr;
printf("version .............. = %u\n", hdr->version);
printf("indexid .............. = %u (%s)\n", hdr->indexid, unixdate2str(hdr->indexid));
printf("file_seq ............. = %u (%s) (%d compressions)\n",
hdr->file_seq, unixdate2str(hdr->file_seq),
hdr->file_seq - hdr->indexid);
printf("continued_record_count = %u\n", hdr->continued_record_count);
printf("hole_offset .......... = %u\n", hdr->hole_offset);
printf("used_file_size ....... = %u\n", hdr->used_file_size);
printf("deleted_space ........ = %u\n", hdr->deleted_space);
printf("field_header_offset .. = %u (0x%08x nontranslated)\n",
mail_index_offset_to_uint32(hdr->field_header_offset),
hdr->field_header_offset);
printf("-- Cache fields --\n");
fields = mail_cache_register_get_list(cache, pool_datastack_create(),
&count);
printf(
" # Name Type Size Dec Last used\n");
for (i = 0; i < cache->file_fields_count; i++) {
cache_idx = cache->file_field_map[i];
field = &fields[cache_idx];
printf("%2u: %-44s %-4s ", i, field->name,
cache_type2str(field->type));
if (field->field_size != (uint32_t)-1 ||
CACHE_TYPE_IS_FIXED_SIZE(field->type))
printf("%4u ", field->field_size);
else
printf(" - ");
printf("%-4s %.16s\n",
cache_decision2str(field->decision),
unixdate2str(cache->fields[cache_idx].last_used));
}
}
static void dump_message_part(string_t *str, const struct message_part *part)
{
for (; part != NULL; part = part->next) {
str_append_c(str, '(');
str_printfa(str, "pos=%"PRIuUOFF_T" ", part->physical_pos);
str_printfa(str, "hdr.p=%"PRIuUOFF_T" ", part->header_size.physical_size);
str_printfa(str, "hdr.v=%"PRIuUOFF_T" ", part->header_size.virtual_size);
str_printfa(str, "body.p=%"PRIuUOFF_T" ", part->body_size.physical_size);
str_printfa(str, "body.v=%"PRIuUOFF_T" ", part->body_size.virtual_size);
str_printfa(str, "flags=%x", part->flags);
if (part->children != NULL) {
str_append_c(str, ' ');
dump_message_part(str, part->children);
}
str_append_c(str, ')');
}
}
static void
dump_cache_mime_parts(string_t *str, const void *data, unsigned int size)
{
const struct message_part *part;
const char *error;
str_append_c(str, ' ');
part = message_part_deserialize(pool_datastack_create(), data, size, &error);
if (part == NULL) {
str_printfa(str, "error: %s", error);
return;
}
dump_message_part(str, part);
}
static void dump_cache(struct mail_cache_view *cache_view, unsigned int seq)
{
struct mail_cache_lookup_iterate_ctx iter;
const struct mail_cache_record *prev_rec = NULL;
const struct mail_cache_field *field;
struct mail_cache_iterate_field iter_field;
const void *data;
unsigned int size;
string_t *str;
int ret;
str = t_str_new(512);
mail_cache_lookup_iter_init(cache_view, seq, &iter);
while ((ret = mail_cache_lookup_iter_next(&iter, &iter_field)) > 0) {
if (iter.rec != prev_rec) {
printf(" - cache offset=%u size=%u, prev_offset = %u\n",
iter.offset, iter.rec->size,
iter.rec->prev_offset);
prev_rec = iter.rec;
}
field = &cache_view->cache->fields[iter_field.field_idx].field;
data = iter_field.data;
size = iter_field.size;
str_truncate(str, 0);
str_printfa(str, " - %s: ", field->name);
switch (field->type) {
case MAIL_CACHE_FIELD_FIXED_SIZE:
if (size == sizeof(uint32_t)) {
uint32_t value;
memcpy(&value, data, sizeof(value));
str_printfa(str, "%u ", value);
} else if (size == sizeof(uint64_t)) {
uint64_t value;
memcpy(&value, data, sizeof(value));
str_printfa(str, "%llu ", (unsigned long long)value);
}
case MAIL_CACHE_FIELD_VARIABLE_SIZE:
case MAIL_CACHE_FIELD_BITMASK:
str_printfa(str, "(%s)", binary_to_hex(data, size));
if (strcmp(field->name, "mime.parts") == 0)
dump_cache_mime_parts(str, data, size);
break;
case MAIL_CACHE_FIELD_STRING:
if (size > 0)
str_printfa(str, "%.*s", (int)size, (const char *)data);
break;
case MAIL_CACHE_FIELD_HEADER: {
const uint32_t *lines = data;
int i;
for (i = 0;; i++) {
if (size < sizeof(uint32_t)) {
if (i == 0 && size == 0) {
/* header doesn't exist */
break;
}
str_append(str, "\n - BROKEN: header field doesn't end with 0 line");
size = 0;
break;
}
size -= sizeof(uint32_t);
data = CONST_PTR_OFFSET(data, sizeof(uint32_t));
if (lines[i] == 0)
break;
if (i > 0)
str_append(str, ", ");
str_printfa(str, "%u", lines[i]);
}
if (i == 1 && size > 0 &&
((const char *)data)[size-1] == '\n')
size--;
if (size > 0)
str_printfa(str, ": %.*s", (int)size, (const char *)data);
break;
}
case MAIL_CACHE_FIELD_COUNT:
i_unreached();
break;
}
printf("%s\n", str_c(str));
}
if (ret < 0)
printf(" - broken cache\n");
}
static const char *flags2str(enum mail_flags flags)
{
string_t *str;
str = t_str_new(64);
str_append_c(str, '(');
if ((flags & MAIL_SEEN) != 0)
str_append(str, "Seen ");
if ((flags & MAIL_ANSWERED) != 0)
str_append(str, "Answered ");
if ((flags & MAIL_FLAGGED) != 0)
str_append(str, "Flagged ");
if ((flags & MAIL_DELETED) != 0)
str_append(str, "Deleted ");
if ((flags & MAIL_DRAFT) != 0)
str_append(str, "Draft ");
if (str_len(str) == 1)
return "";
str_truncate(str, str_len(str)-1);
str_append_c(str, ')');
return str_c(str);
}
static void dump_record(struct mail_index_view *view, unsigned int seq)
{
struct mail_index *index = mail_index_view_get_index(view);
const struct mail_index_record *rec;
const struct mail_index_registered_ext *ext;
const void *data;
unsigned int i, ext_count;
string_t *str;
bool expunged;
rec = mail_index_lookup(view, seq);
printf("RECORD: seq=%u, uid=%u, flags=0x%02x %s\n",
seq, rec->uid, rec->flags, flags2str(rec->flags));
str = t_str_new(256);
ext = array_get(&index->extensions, &ext_count);
for (i = 0; i < ext_count; i++) {
mail_index_lookup_ext(view, seq, i, &data, &expunged);
if (data == NULL || ext[i].record_size == 0)
continue;
str_truncate(str, 0);
str_printfa(str, " - ext %d %-10s: ", i, ext[i].name);
if (ext[i].record_size == sizeof(uint16_t) &&
ext[i].record_align == sizeof(uint16_t))
str_printfa(str, "%10u", *((const uint16_t *)data));
else if (ext[i].record_size == sizeof(uint32_t) &&
ext[i].record_align == sizeof(uint32_t))
str_printfa(str, "%10u", *((const uint32_t *)data));
else if (ext[i].record_size == sizeof(uint64_t) &&
ext[i].record_align == sizeof(uint64_t)) {
uint64_t value = *((const uint64_t *)data);
str_printfa(str, "%10llu", (unsigned long long)value);
} else {
str_append(str, " ");
}
str_printfa(str, " (%s)",
binary_to_hex(data, ext[i].record_size));
printf("%s\n", str_c(str));
if (strcmp(ext[i].name, "virtual") == 0) {
const struct virtual_mail_index_record *vrec = data;
printf(" : mailbox_id = %u\n", vrec->mailbox_id);
printf(" : real_uid = %u\n", vrec->real_uid);
} else if (strcmp(ext[i].name, "map") == 0) {
const struct mdbox_mail_index_map_record *mrec = data;
printf(" : file_id = %u\n", mrec->file_id);
printf(" : offset = %u\n", mrec->offset);
printf(" : size = %u\n", mrec->size);
} else if (strcmp(ext[i].name, "mdbox") == 0) {
const struct mdbox_mail_index_record *drec = data;
printf(" : map_uid = %u\n", drec->map_uid);
printf(" : save_date = %u (%s)\n", drec->save_date, unixdate2str(drec->save_date));
}
}
}
static bool dir_has_index(const char *dir, const char *name)
{
struct stat st;
return stat(t_strconcat(dir, "/", name, NULL), &st) == 0 ||
stat(t_strconcat(dir, "/", name, ".log", NULL), &st) == 0;
}
static struct mail_index *path_open_index(const char *path)
{
struct stat st;
const char *p;
if (stat(path, &st) == 0 && S_ISDIR(st.st_mode)) {
if (dir_has_index(path, "dovecot.index"))
return mail_index_alloc(path, "dovecot.index");
else if (dir_has_index(path, "dovecot.map.index"))
return mail_index_alloc(path, "dovecot.map.index");
else
return NULL;
} else if ((p = strrchr(path, '/')) != NULL)
return mail_index_alloc(t_strdup_until(path, p), p + 1);
else
return mail_index_alloc(".", path);
}
static void cmd_dump_index(int argc ATTR_UNUSED, char *argv[])
{
struct mail_index *index;
struct mail_index_view *view;
struct mail_cache_view *cache_view;
unsigned int seq, uid = 0;
index = path_open_index(argv[1]);
if (index == NULL ||
mail_index_open(index, MAIL_INDEX_OPEN_FLAG_READONLY) <= 0)
i_fatal("Couldn't open index %s", argv[1]);
if (argv[2] != NULL)
uid = atoi(argv[2]);
view = mail_index_view_open(index);
cache_view = mail_cache_view_open(index->cache, view);
if (uid == 0) {
printf("-- INDEX: %s\n", index->filepath);
dump_hdr(index);
dump_extensions(index);
dump_keywords(index);
printf("\n-- CACHE: %s\n", index->cache->filepath);
dump_cache_hdr(index->cache);
printf("\n-- RECORDS: %u\n", index->map->hdr.messages_count);
}
for (seq = 1; seq <= index->map->hdr.messages_count; seq++) {
if (uid == 0 || mail_index_lookup(view, seq)->uid == uid) {
T_BEGIN {
dump_record(view, seq);
dump_cache(cache_view, seq);
printf("\n");
} T_END;
}
}
mail_cache_view_close(&cache_view);
mail_index_view_close(&view);
mail_index_close(index);
mail_index_free(&index);
}
static bool test_dump_index(const char *path)
{
struct mail_index *index;
bool ret;
index = path_open_index(path);
if (index == NULL)
return FALSE;
ret = mail_index_open(index, MAIL_INDEX_OPEN_FLAG_READONLY) > 0;
if (ret > 0)
mail_index_close(index);
mail_index_free(&index);
return ret;
}
struct doveadm_cmd_dump doveadm_cmd_dump_index = {
"index",
test_dump_index,
cmd_dump_index
};