<64bit big-endian: settings full size>
<32bit big-endian: event filter strings count>
- <NUL-terminated string: event filter string>[count]
+ Repeat for "event filter strings count":
+ <NUL-terminated string: event filter string>
+ <NUL-terminated string: override event filter string>
Repeat until "settings full size" is reached:
<64bit big-endian: settings block size>
static void
config_dump_full_append_filter_query(string_t *str,
const struct config_filter *filter,
- bool leaf, bool parent_hierarchical)
+ bool leaf, bool parent_hierarchical,
+ bool write_named_filters)
{
if (filter->service != NULL) {
if (filter->service[0] != '!') {
return;
}
- str_printfa(str, SETTINGS_EVENT_FILTER_NAME"=\"%s\" AND ",
- wildcard_str_escape(filter_name));
+ if (write_named_filters || filter->filter_hierarchical) {
+ str_printfa(str, SETTINGS_EVENT_FILTER_NAME"=\"%s\" AND ",
+ wildcard_str_escape(filter_name));
+ }
}
}
static void
config_dump_full_append_filter(string_t *str,
- const struct config_filter *filter)
+ const struct config_filter *filter,
+ bool write_named_filters)
{
bool leaf = TRUE;
bool parent_hierarchical = FALSE;
do {
config_dump_full_append_filter_query(str, filter, leaf,
- parent_hierarchical);
+ parent_hierarchical,
+ write_named_filters);
leaf = FALSE;
parent_hierarchical = filter->filter_hierarchical;
filter = filter->parent;
} while (filter != NULL);
- str_truncate(str, str_len(str) - 5);
+ if (str_len(str) > 0)
+ str_truncate(str, str_len(str) - 5);
}
static void
/* the first filter is the global empty filter */
o_stream_nsend(output, "", 1);
+ o_stream_nsend(output, "", 1);
string_t *str = str_new(default_pool, 128);
for (i = 1; i < filter_count; i++) T_BEGIN {
str_truncate(str, 0);
- config_dump_full_append_filter(str, &filters[i]->filter);
+ config_dump_full_append_filter(str, &filters[i]->filter, TRUE);
+ str_append_c(str, '\0');
+ o_stream_nsend(output, str_data(str), str_len(str));
+
+ str_truncate(str, 0);
+ config_dump_full_append_filter(str, &filters[i]->filter, FALSE);
str_append_c(str, '\0');
o_stream_nsend(output, str_data(str), str_len(str));
} T_END;
if (!ctx->filter_written) {
string_t *str = t_str_new(128);
str_append(str, ":FILTER ");
- config_dump_full_append_filter(str, ctx->filter);
+ config_dump_full_append_filter(str, ctx->filter, TRUE);
str_append_c(str, '\n');
o_stream_nsend(ctx->output, str_data(str), str_len(str));
ctx->filter_written = TRUE;
/* full file size is 7 bytes, which makes the first block size
truncated, since it needs 8 bytes */
{ DATA("DOVECOT-CONFIG\t1.0\n"
- "\x00\x00\x00\x00\x00\x00\x00\x0C" // full size
+ "\x00\x00\x00\x00\x00\x00\x00\x0D" // full size
"\x00\x00\x00\x01" // event filter count
"\x00" // event filter[0]
+ "\x00" // override event filter[0]
"\x00\x00\x00\x00\x00\x00\x00"), // block size
"Area too small when reading size of 'block size'" },
/* first block size is 0, which is too small */
{ DATA("DOVECOT-CONFIG\t1.0\n"
- "\x00\x00\x00\x00\x00\x00\x00\x0D" // full size
+ "\x00\x00\x00\x00\x00\x00\x00\x0E" // full size
"\x00\x00\x00\x01" // event filter count
"\x00" // event filter[0]
+ "\x00" // override event filter[0]
"\x00\x00\x00\x00\x00\x00\x00\x00"), // block size
"'block name' points outside area" },
/* first block size is 1, but full file size is too small */
{ DATA("DOVECOT-CONFIG\t1.0\n"
- "\x00\x00\x00\x00\x00\x00\x00\x0D" // full size
+ "\x00\x00\x00\x00\x00\x00\x00\x0E" // full size
"\x00\x00\x00\x01" // event filter count
"\x00" // event filter[0]
+ "\x00" // override event filter[0]
"\x00\x00\x00\x00\x00\x00\x00\x01"), // block size
"'block size' points outside are" },
/* block name is not NUL-terminated */
{ DATA("DOVECOT-CONFIG\t1.0\n"
- "\x00\x00\x00\x00\x00\x00\x00\x0F" // full size
+ "\x00\x00\x00\x00\x00\x00\x00\x10" // full size
"\x00\x00\x00\x01" // event filter count
"\x00" // event filter[0]
+ "\x00" // override event filter[0]
"\x00\x00\x00\x00\x00\x00\x00\x01" // block size
"N"
"\x00"), // trailing garbage so we can have NUL
/* settings count is truncated */
{ DATA("DOVECOT-CONFIG\t1.0\n"
- "\x00\x00\x00\x00\x00\x00\x00\x12" // full size
+ "\x00\x00\x00\x00\x00\x00\x00\x13" // full size
"\x00\x00\x00\x01" // event filter count
"\x00" // event filter[0]
+ "\x00" // override event filter[0]
"\x00\x00\x00\x00\x00\x00\x00\x05" // block size
"N\x00" // block name
"\x00\x00\x00"),
/* settings keys are truncated */
{ DATA("DOVECOT-CONFIG\t1.0\n"
- "\x00\x00\x00\x00\x00\x00\x00\x13" // full size
+ "\x00\x00\x00\x00\x00\x00\x00\x14" // full size
"\x00\x00\x00\x01" // event filter count
"\x00" // event filter[0]
+ "\x00" // override event filter[0]
"\x00\x00\x00\x00\x00\x00\x00\x06" // block size
"N\x00" // block name
"\x00\x00\x01\x00"), // settings count
/* base settings size is truncated */
{ DATA("DOVECOT-CONFIG\t1.0\n"
- "\x00\x00\x00\x00\x00\x00\x00\x1C" // full size
+ "\x00\x00\x00\x00\x00\x00\x00\x1D" // full size
"\x00\x00\x00\x01" // event filter count
"\x00" // event filter[0]
+ "\x00" // override event filter[0]
"\x00\x00\x00\x00\x00\x00\x00\x0F" // block size
"N\x00" // block name
"\x00\x00\x00\x01" // settings count
"Area too small when reading size of 'base settings size'" },
/* base settings size is zero */
{ DATA("DOVECOT-CONFIG\t1.0\n"
- "\x00\x00\x00\x00\x00\x00\x00\x1D" // full size
+ "\x00\x00\x00\x00\x00\x00\x00\x1E" // full size
"\x00\x00\x00\x01" // event filter count
"\x00" // event filter[0]
+ "\x00" // override event filter[0]
"\x00\x00\x00\x00\x00\x00\x00\x10" // block size
"N\x00" // block name
"\x00\x00\x00\x01" // settings count
"'base settings error' points outside area" },
/* base settings error is not NUL-terminated */
{ DATA("DOVECOT-CONFIG\t1.0\n"
- "\x00\x00\x00\x00\x00\x00\x00\x1F" // full size
+ "\x00\x00\x00\x00\x00\x00\x00\x20" // full size
"\x00\x00\x00\x01" // event filter count
"\x00" // event filter[0]
+ "\x00" // override event filter[0]
"\x00\x00\x00\x00\x00\x00\x00\x12" // block size
"N\x00" // block name
"\x00\x00\x00\x01" // settings count
/* filter count is truncated */
{ DATA("DOVECOT-CONFIG\t1.0\n"
- "\x00\x00\x00\x00\x00\x00\x00\x21" // full size
+ "\x00\x00\x00\x00\x00\x00\x00\x22" // full size
"\x00\x00\x00\x01" // event filter count
"\x00" // event filter[0]
+ "\x00" // override event filter[0]
"\x00\x00\x00\x00\x00\x00\x00\x14" // block size
"N\x00" // block name
"\x00\x00\x00\x01" // settings count
/* filter settings size is truncated */
{ DATA("DOVECOT-CONFIG\t1.0\n"
- "\x00\x00\x00\x00\x00\x00\x00\x29" // full size
+ "\x00\x00\x00\x00\x00\x00\x00\x2A" // full size
"\x00\x00\x00\x01" // event filter count
"\x00" // event filter[0]
+ "\x00" // override event filter[0]
"\x00\x00\x00\x00\x00\x00\x00\x1B" // block size
"N\x00" // block name
"\x00\x00\x00\x01" // settings count
/* filter settings is truncated */
{ DATA("DOVECOT-CONFIG\t1.0\n"
- "\x00\x00\x00\x00\x00\x00\x00\x2A" // full size
+ "\x00\x00\x00\x00\x00\x00\x00\x2B" // full size
"\x00\x00\x00\x01" // event filter count
"\x00" // event filter[0]
+ "\x00" // override event filter[0]
"\x00\x00\x00\x00\x00\x00\x00\x1D" // block size
"N\x00" // block name
"\x00\x00\x00\x01" // settings count
"'filter settings size' points outside area" },
/* filter error is missing */
{ DATA("DOVECOT-CONFIG\t1.0\n"
- "\x00\x00\x00\x00\x00\x00\x00\x37" // full size
+ "\x00\x00\x00\x00\x00\x00\x00\x38" // full size
"\x00\x00\x00\x01" // event filter count
"\x00" // event filter[0]
+ "\x00" // override event filter[0]
"\x00\x00\x00\x00\x00\x00\x00\x2A" // block size
"N\x00" // block name
"\x00\x00\x00\x01" // settings count
"'filter error string' points outside area" },
/* filter error is not NUL-terminated */
{ DATA("DOVECOT-CONFIG\t1.0\n"
- "\x00\x00\x00\x00\x00\x00\x00\x45" // full size
+ "\x00\x00\x00\x00\x00\x00\x00\x46" // full size
"\x00\x00\x00\x01" // event filter count
"\x00" // event filter[0]
+ "\x00" // override event filter[0]
"\x00\x00\x00\x00\x00\x00\x00\x38" // block size
"master_service\x00" // block name
"\x00\x00\x00\x01" // settings count
"'filter error string' points outside area" },
/* invalid filter string */
{ DATA("DOVECOT-CONFIG\t1.0\n"
- "\x00\x00\x00\x00\x00\x00\x00\x39" // full size
+ "\x00\x00\x00\x00\x00\x00\x00\x3B" // full size
"\x00\x00\x00\x01" // event filter count
"F\x00" // event filter[0]
+ "F\x00" // override event filter[0]
"\x00\x00\x00\x00\x00\x00\x00\x2B" // block size
"N\x00" // block name
"\x00\x00\x00\x01" // settings count
/* Duplicate block name */
{ DATA("DOVECOT-CONFIG\t1.0\n"
- "\x00\x00\x00\x00\x00\x00\x00\x42" // full size
+ "\x00\x00\x00\x00\x00\x00\x00\x43" // full size
"\x00\x00\x00\x01" // event filter count
"\x00" // event filter[0]
+ "\x00" // override event filter[0]
"\x00\x00\x00\x00\x00\x00\x00\x2B" // block size
"N\x00" // block name
"\x00\x00\x00\x01" // settings count
size_t mmap_size;
struct event_filter **event_filters;
+ struct event_filter **override_event_filters;
unsigned int event_filters_count;
HASH_TABLE(const char *, struct settings_mmap_block *) blocks;
mmap->event_filters = mmap->event_filters_count == 0 ? NULL :
p_new(mmap->pool, struct event_filter *, mmap->event_filters_count);
+ mmap->override_event_filters = mmap->event_filters_count == 0 ? NULL :
+ p_new(mmap->pool, struct event_filter *, mmap->event_filters_count);
- for (uint32_t i = 0; i < mmap->event_filters_count; i++) {
+ for (uint32_t i = 0; i < 2 * mmap->event_filters_count; i++) {
+ struct event_filter **filter_dest =
+ i % 2 == 0 ? &mmap->event_filters[i / 2] :
+ &mmap->override_event_filters[i / 2];
if (settings_block_read_str(mmap, offset, mmap->mmap_size,
"filter string", &filter_string,
error_r) < 0)
return -1;
if (filter_string[0] == '\0') {
- mmap->event_filters[i] = EVENT_FILTER_MATCH_ALWAYS;
+ *filter_dest = EVENT_FILTER_MATCH_ALWAYS;
continue;
}
(strcmp(mmap->root->protocol_name, value) == 0) == op_not &&
(flags & SETTINGS_READ_NO_PROTOCOL_FILTER) == 0) {
/* protocol doesn't match */
- mmap->event_filters[i] = EVENT_FILTER_MATCH_NEVER;
+ *filter_dest = EVENT_FILTER_MATCH_NEVER;
event_filter_unref(&tmp_filter);
continue;
}
if (value != NULL && service_name != NULL &&
(strcmp(value, service_name) == 0) == op_not) {
/* service name doesn't match */
- mmap->event_filters[i] = EVENT_FILTER_MATCH_NEVER;
+ *filter_dest = EVENT_FILTER_MATCH_NEVER;
event_filter_unref(&tmp_filter);
continue;
}
- mmap->event_filters[i] = event_filter_create_with_pool(mmap->pool);
+ *filter_dest = event_filter_create_with_pool(mmap->pool);
pool_ref(mmap->pool);
- event_filter_merge(mmap->event_filters[i], tmp_filter,
+ event_filter_merge(*filter_dest, tmp_filter,
EVENT_FILTER_MERGE_OP_OR);
event_filter_unref(&tmp_filter);
}
if (event_filter != EVENT_FILTER_MATCH_ALWAYS) {
int ret = settings_instance_override(ctx,
- event_filter, error_r);
+ mmap->override_event_filters[event_filter_idx],
+ error_r);
if (ret < 0)
return -1;
if (ret > 0)
if (mmap->event_filters[i] != EVENT_FILTER_MATCH_ALWAYS &&
mmap->event_filters[i] != EVENT_FILTER_MATCH_NEVER)
event_filter_unref(&mmap->event_filters[i]);
+ if (mmap->override_event_filters[i] != EVENT_FILTER_MATCH_ALWAYS &&
+ mmap->override_event_filters[i] != EVENT_FILTER_MATCH_NEVER)
+ event_filter_unref(&mmap->override_event_filters[i]);
}
hash_table_destroy(&mmap->blocks);
the overrides that have a matching filter. This preserves
the expected order in which settings are applied. */
if (event_filter != NULL && !set->always_match &&
+ event_filter != EVENT_FILTER_MATCH_ALWAYS &&
(set->filter_event == NULL ||
!event_filter_match(event_filter, set->filter_event,
&failure_ctx)))