summaryrefslogtreecommitdiffstats
path: root/src/plugins/fts/doveadm-dump-fts-expunge-log.c
blob: 7438bca8ad52bba68034352b6d87de702de14ed9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
/* Copyright (c) 2011-2018 Dovecot authors, see the included COPYING file */

#include "lib.h"
#include "buffer.h"
#include "hex-binary.h"
#include "guid.h"
#include "doveadm-dump.h"
#include "doveadm-fts.h"

#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>

struct fts_expunge_log_record {
	uint32_t checksum;
	uint32_t record_size;
	guid_128_t guid;
};

static int dump_record(int fd, buffer_t *buf)
{
	struct fts_expunge_log_record rec;
	off_t offset;
	void *data;
	const uint32_t *expunges, *uids;
	ssize_t ret;
	size_t data_size;
	unsigned int i, uids_count;

	offset = lseek(fd, 0, SEEK_CUR);

	ret = read(fd, &rec, sizeof(rec));
	if (ret == 0)
		return 0;

	if (ret != sizeof(rec))
		i_fatal("rec read() %d != %d", (int)ret, (int)sizeof(rec));

	if (rec.record_size < sizeof(rec) + sizeof(uint32_t) ||
	    rec.record_size > INT_MAX) {
		i_fatal("Invalid record_size=%u at offset %"PRIuUOFF_T,
			rec.record_size, offset);
	}
	data_size = rec.record_size - sizeof(rec);
	buffer_set_used_size(buf, 0);
	data = buffer_append_space_unsafe(buf, data_size);
	ret = read(fd, data, data_size);
	if (ret != (ssize_t)data_size)
		i_fatal("rec read() %d != %d", (int)ret, (int)data_size);

	printf("#%"PRIuUOFF_T":\n", offset);
	printf("  checksum  = %8x\n", rec.checksum);
	printf("  size .... = %u\n", rec.record_size);
	printf("  mailbox . = %s\n", guid_128_to_string(rec.guid));

	expunges = CONST_PTR_OFFSET(data, data_size - sizeof(uint32_t));
	printf("  expunges  = %u\n", *expunges);

	printf("  uids .... = ");

	uids = data;
	uids_count = (rec.record_size - sizeof(rec) - sizeof(uint32_t)) /
		sizeof(uint32_t);
	for (i = 0; i < uids_count; i += 2) {
		if (i != 0)
			printf(",");
		if (uids[i] == uids[i+1])
			printf("%u", uids[i]);
		else
			printf("%u-%u", uids[i], uids[i+1]);
	}
	printf("\n");
	return 1;
}

static void
cmd_dump_fts_expunge_log(const char *path, const char *const *args ATTR_UNUSED)
{
	buffer_t *buf;
	int fd, ret;

	fd = open(path, O_RDONLY);
	if (fd < 0)
		i_fatal("open(%s) failed: %m", path);

	buf = buffer_create_dynamic(default_pool, 1024);
	do {
		T_BEGIN {
			ret = dump_record(fd, buf);
		} T_END;
	} while (ret > 0);
	buffer_free(&buf);
	i_close_fd(&fd);
}

static bool test_dump_fts_expunge_log(const char *path)
{
	const char *p;

	if ((p = strrchr(path, '/')) != NULL)
		p++;
	else
		p = path;
	return strcmp(p, "dovecot-expunges.log") == 0;
}

static const struct doveadm_cmd_dump doveadm_cmd_dump_fts_expunge_log = {
	"fts-expunge-log",
	test_dump_fts_expunge_log,
	cmd_dump_fts_expunge_log
};

void doveadm_dump_fts_expunge_log_init(void)
{
	doveadm_dump_register(&doveadm_cmd_dump_fts_expunge_log);
}