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
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
|
/* Copyright (c) 2009-2018 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "buffer.h"
#include "test-common.h"
#include "mail-index-private.h"
#include "mail-transaction-log-private.h"
#include <sys/stat.h>
static bool log_lock_failure = FALSE;
void mail_index_file_set_syscall_error(struct mail_index *index ATTR_UNUSED,
const char *filepath ATTR_UNUSED,
const char *function ATTR_UNUSED)
{
}
int mail_transaction_log_lock_head(struct mail_transaction_log *log ATTR_UNUSED,
const char *lock_reason ATTR_UNUSED)
{
return log_lock_failure ? -1 : 0;
}
void mail_transaction_log_file_unlock(struct mail_transaction_log_file *file ATTR_UNUSED,
const char *lock_reason ATTR_UNUSED) {}
void mail_transaction_update_modseq(const struct mail_transaction_header *hdr,
const void *data ATTR_UNUSED,
uint64_t *cur_modseq,
unsigned int version ATTR_UNUSED)
{
if ((hdr->type & MAIL_TRANSACTION_EXPUNGE) != 0)
*cur_modseq += 1;
}
int mail_index_move_to_memory(struct mail_index *index ATTR_UNUSED)
{
return -1;
}
static void test_append_expunge(struct mail_transaction_log *log)
{
static unsigned int buf[] = { 0x12345678, 0xabcdef09 };
struct mail_transaction_log_file *file = log->head;
struct mail_transaction_log_append_ctx *ctx;
const struct mail_transaction_header *hdr;
const unsigned int *bufp;
const struct mail_transaction_boundary *bound;
test_assert(mail_transaction_log_append_begin(log->index, MAIL_TRANSACTION_EXTERNAL, &ctx) == 0);
mail_transaction_log_append_add(ctx, MAIL_TRANSACTION_APPEND,
&buf[0], sizeof(buf[0]));
test_assert(ctx->new_highest_modseq == 0);
mail_transaction_log_append_add(ctx, MAIL_TRANSACTION_EXPUNGE,
&buf[1], sizeof(buf[1]));
test_assert(ctx->new_highest_modseq == 1);
test_assert(mail_transaction_log_append_commit(&ctx) == 0);
test_assert(file->sync_highest_modseq == 1);
test_assert(file->sync_offset == file->buffer_offset + file->buffer->used);
hdr = file->buffer->data;
test_assert(hdr->type == (MAIL_TRANSACTION_BOUNDARY |
MAIL_TRANSACTION_EXTERNAL));
test_assert(mail_index_offset_to_uint32(hdr->size) == sizeof(*hdr) + sizeof(*bound));
bound = (const void *)(hdr + 1);
test_assert(bound->size == file->buffer->used);
hdr = (const void *)(bound + 1);
test_assert(hdr->type == (MAIL_TRANSACTION_APPEND |
MAIL_TRANSACTION_EXTERNAL));
test_assert(mail_index_offset_to_uint32(hdr->size) == sizeof(*hdr) + sizeof(buf[0]));
bufp = (const void *)(hdr + 1);
test_assert(*bufp == buf[0]);
hdr = (const void *)(bufp + 1);
test_assert(hdr->type == (MAIL_TRANSACTION_EXPUNGE |
MAIL_TRANSACTION_EXPUNGE_PROT |
MAIL_TRANSACTION_EXTERNAL));
test_assert(mail_index_offset_to_uint32(hdr->size) == sizeof(*hdr) + sizeof(buf[0]));
bufp = (const void *)(hdr + 1);
test_assert(*bufp == buf[1]);
test_assert(file->buffer->used == (size_t)((const char *)(bufp+1) - (const char *)file->buffer->data));
buffer_set_used_size(file->buffer, 0);
file->buffer_offset = 0;
test_end();
}
static void test_append_sync_offset(struct mail_transaction_log *log)
{
struct mail_transaction_log_file *file = log->head;
struct mail_transaction_log_append_ctx *ctx;
const struct mail_transaction_header *hdr;
const struct mail_transaction_header_update *u;
const uint32_t *offsetp;
test_begin("transaction log append: append_sync_offset only");
test_assert(mail_transaction_log_append_begin(log->index, 0, &ctx) == 0);
ctx->index_sync_transaction = TRUE;
file->max_tail_offset = 123;
test_assert(mail_transaction_log_append_commit(&ctx) == 0);
test_assert(file->buffer->used == sizeof(*hdr) + sizeof(*u) + sizeof(*offsetp));
hdr = file->buffer->data;
test_assert(hdr->type == MAIL_TRANSACTION_HEADER_UPDATE);
test_assert(mail_index_offset_to_uint32(hdr->size) == file->buffer->used);
u = (const void *)(hdr + 1);
test_assert(u->offset == offsetof(struct mail_index_header, log_file_tail_offset));
test_assert(u->size == sizeof(*offsetp));
offsetp = (const void *)(u+1);
test_assert(*offsetp == 123);
test_end();
}
static void test_mail_transaction_log_append(void)
{
struct mail_transaction_log *log;
struct mail_transaction_log_file *file;
struct mail_transaction_log_append_ctx *ctx;
char tmp_path[] = "/tmp/dovecot.test.XXXXXX";
struct stat st;
int fd;
fd = mkstemp(tmp_path);
if (fd == -1)
i_fatal("mkstemp(%s) failed: %m", tmp_path);
test_begin("transaction log append");
log = i_new(struct mail_transaction_log, 1);
log->index = i_new(struct mail_index, 1);
log->index->log = log;
log->head = file = i_new(struct mail_transaction_log_file, 1);
file->fd = -1;
test_append_expunge(log);
test_begin("transaction log append: lock failure");
log_lock_failure = TRUE;
test_assert(mail_transaction_log_append_begin(log->index, 0, &ctx) < 0);
log_lock_failure = FALSE;
test_end();
test_append_sync_offset(log);
/* do this after head->buffer has already been initialized */
test_begin("transaction log append: garbage truncation");
file->sync_offset = 1;
file->buffer_offset = 1;
file->last_size = 3;
file->fd = fd;
test_assert(mail_transaction_log_append_begin(log->index, 0, &ctx) == 0);
test_assert(mail_transaction_log_append_commit(&ctx) == 0);
if (fstat(fd, &st) < 0) i_fatal("fstat() failed: %m");
test_assert(st.st_size == 1);
file->fd = -1;
test_end();
buffer_free(&log->head->buffer);
i_free(log->head);
i_free(log->index);
i_free(log);
i_unlink(tmp_path);
}
int main(void)
{
static void (*const test_functions[])(void) = {
test_mail_transaction_log_append,
NULL
};
return test_run(test_functions);
}
|