Merge branch 'fix/audit-filterx' into fix/audit-cycle
This commit is contained in:
@@ -16,6 +16,7 @@
|
||||
#include "test_file.h"
|
||||
#include "test_file_list.h"
|
||||
#include "test_file_sendfile.h"
|
||||
#include "test_filter.h"
|
||||
#include "test_format.h"
|
||||
#include "test_fuzz_smoke.h"
|
||||
#include "test_glob.h"
|
||||
@@ -80,6 +81,7 @@ int main() {
|
||||
RUN_TEST(test_receiver_timeout);
|
||||
RUN_TEST(test_metadata);
|
||||
RUN_TEST(test_glob);
|
||||
RUN_TEST(test_filter);
|
||||
RUN_TEST(test_iconv);
|
||||
RUN_TEST(test_file);
|
||||
RUN_TEST(test_file_list);
|
||||
|
||||
@@ -0,0 +1,222 @@
|
||||
#include "test_filter.h"
|
||||
#include "filter.h"
|
||||
#include "test_utils.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
/* Every `-f`/`--filter` rule string is validated through the list parser, so
|
||||
* the list parser must reject the modifiers the standalone parser rejects
|
||||
* rather than silently folding them into a pattern. */
|
||||
|
||||
static void test_filter_list_rejects_xattr_modifier() {
|
||||
static const char* const rules[] = {
|
||||
"-x user.foo", /* short exclude + x */
|
||||
"exclude,x user.foo", /* long exclude + x */
|
||||
"+x user.foo", /* include + x */
|
||||
"hide,x *.tmp", /* hide + x */
|
||||
"dir-merge,x .rules", /* x must not be dropped on dir-merge */
|
||||
"merge,x /tmp/nonexistent" /* x must not be dropped on merge */
|
||||
};
|
||||
for (size_t i = 0; i < sizeof(rules) / sizeof(rules[0]); i++) {
|
||||
FilterRuleList* list = filter_rule_list_create();
|
||||
EXPECT_NOT_NULL(list);
|
||||
char err[256] = "";
|
||||
bool ok = filter_rule_list_parse_append(list, rules[i], NULL, NULL, err, sizeof(err));
|
||||
EXPECT_FALSE(ok);
|
||||
EXPECT_TRUE(strstr(err, "xattr") != NULL);
|
||||
filter_rule_list_free(list);
|
||||
}
|
||||
|
||||
/* A bare "x" is not a rule at all: rejected as generic bad syntax. */
|
||||
FilterRuleList* list = filter_rule_list_create();
|
||||
EXPECT_NOT_NULL(list);
|
||||
char err[256] = "";
|
||||
EXPECT_FALSE(filter_rule_list_parse_append(list, "x user.foo", NULL, NULL, err, sizeof(err)));
|
||||
EXPECT_TRUE(err[0] != '\0');
|
||||
filter_rule_list_free(list);
|
||||
}
|
||||
|
||||
static void test_filter_list_rejects_unsupported_modifiers() {
|
||||
static const char* const rules[] = {
|
||||
"-e foo", /* e: merge-only in rsync */
|
||||
"-n foo", /* n: merge-only in rsync */
|
||||
"-w foo", /* w: merge-only in rsync */
|
||||
"merge,n /tmp/x", ".e /tmp/x", "dir-merge,e .rules", "exclude,w foo",
|
||||
};
|
||||
for (size_t i = 0; i < sizeof(rules) / sizeof(rules[0]); i++) {
|
||||
FilterRuleList* list = filter_rule_list_create();
|
||||
EXPECT_NOT_NULL(list);
|
||||
char err[256] = "";
|
||||
bool ok = filter_rule_list_parse_append(list, rules[i], NULL, NULL, err, sizeof(err));
|
||||
EXPECT_FALSE(ok);
|
||||
EXPECT_TRUE(strstr(err, "unsupported filter modifier") != NULL);
|
||||
filter_rule_list_free(list);
|
||||
}
|
||||
}
|
||||
|
||||
static void test_filter_list_accepts_supported_rules_and_modifiers() {
|
||||
static const char* const rules[] = {
|
||||
"- *.tmp", "+ /a.txt", "-s foo", "-r foo", "-p foo",
|
||||
"-! *.o", "-/ foo", "hide *.tmp", "show *.txt", "protect *.bak",
|
||||
"risk *.o", "dir-merge .rules", "-C",
|
||||
};
|
||||
for (size_t i = 0; i < sizeof(rules) / sizeof(rules[0]); i++) {
|
||||
FilterRuleList* list = filter_rule_list_create();
|
||||
EXPECT_NOT_NULL(list);
|
||||
char err[256] = "";
|
||||
bool ok = filter_rule_list_parse_append(list, rules[i], NULL, NULL, err, sizeof(err));
|
||||
if (!ok)
|
||||
printf(" rule '%s' errored: %s\n", rules[i], err);
|
||||
EXPECT_TRUE(ok);
|
||||
filter_rule_list_free(list);
|
||||
}
|
||||
|
||||
/* A glued word is a pattern, not a modifier run (no separator). */
|
||||
{
|
||||
FilterRuleList* list = filter_rule_list_create();
|
||||
char err[128] = "";
|
||||
EXPECT_TRUE(filter_rule_list_parse_append(list, "-newfile", NULL, NULL, err, sizeof(err)));
|
||||
EXPECT_EQ_INT(list->count, 1);
|
||||
EXPECT_EQ_STR(list->items[0]->pattern, "newfile");
|
||||
filter_rule_list_free(list);
|
||||
|
||||
list = filter_rule_list_create();
|
||||
EXPECT_TRUE(filter_rule_list_parse_append(list, "-e2e", NULL, NULL, err, sizeof(err)));
|
||||
EXPECT_EQ_INT(list->count, 1);
|
||||
EXPECT_EQ_STR(list->items[0]->pattern, "e2e");
|
||||
filter_rule_list_free(list);
|
||||
|
||||
list = filter_rule_list_create();
|
||||
EXPECT_TRUE(filter_rule_list_parse_append(list, "-*.o", NULL, NULL, err, sizeof(err)));
|
||||
EXPECT_EQ_INT(list->count, 1);
|
||||
EXPECT_EQ_STR(list->items[0]->pattern, "*.o");
|
||||
filter_rule_list_free(list);
|
||||
|
||||
/* A comma with no modifier still treats the rest as the pattern. */
|
||||
list = filter_rule_list_create();
|
||||
EXPECT_TRUE(filter_rule_list_parse_append(list, "exclude,foo", NULL, NULL, err, sizeof(err)));
|
||||
EXPECT_EQ_INT(list->count, 1);
|
||||
EXPECT_EQ_STR(list->items[0]->pattern, "foo");
|
||||
filter_rule_list_free(list);
|
||||
}
|
||||
|
||||
/* `!` clears the list. */
|
||||
{
|
||||
FilterRuleList* list = filter_rule_list_create();
|
||||
char err[128] = "";
|
||||
EXPECT_TRUE(filter_rule_list_parse_append(list, "- *.tmp", NULL, NULL, err, sizeof(err)));
|
||||
EXPECT_EQ_INT(list->count, 1);
|
||||
EXPECT_TRUE(filter_rule_list_parse_append(list, "!", NULL, NULL, err, sizeof(err)));
|
||||
EXPECT_EQ_INT(list->count, 0);
|
||||
filter_rule_list_free(list);
|
||||
}
|
||||
|
||||
/* -C injects the CVS defaults. */
|
||||
{
|
||||
FilterRuleList* list = filter_rule_list_create();
|
||||
char err[128] = "";
|
||||
EXPECT_TRUE(filter_rule_list_parse_append(list, "-C", NULL, NULL, err, sizeof(err)));
|
||||
EXPECT_TRUE(list->count > 0);
|
||||
filter_rule_list_free(list);
|
||||
}
|
||||
}
|
||||
|
||||
static void test_filter_list_merge_file_still_supported() {
|
||||
char tmpl[] = "/tmp/fastsync_filter_XXXXXX";
|
||||
EXPECT_TRUE(mkdtemp(tmpl) != NULL);
|
||||
char path[512];
|
||||
snprintf(path, sizeof(path), "%s/rules", tmpl);
|
||||
FILE* fp = fopen(path, "w");
|
||||
EXPECT_NOT_NULL(fp);
|
||||
fputs("- *.tmp\n", fp);
|
||||
fclose(fp);
|
||||
|
||||
FilterRuleList* list = filter_rule_list_create();
|
||||
char err[256] = "";
|
||||
char rule[600];
|
||||
snprintf(rule, sizeof(rule), "merge %s", path);
|
||||
EXPECT_TRUE(filter_rule_list_parse_append(list, rule, NULL, NULL, err, sizeof(err)));
|
||||
EXPECT_EQ_INT(list->count, 1);
|
||||
filter_rule_list_free(list);
|
||||
|
||||
/* The same merge with the x modifier is rejected, not silently read. */
|
||||
list = filter_rule_list_create();
|
||||
snprintf(rule, sizeof(rule), "merge,x %s", path);
|
||||
EXPECT_FALSE(filter_rule_list_parse_append(list, rule, NULL, NULL, err, sizeof(err)));
|
||||
EXPECT_TRUE(strstr(err, "xattr") != NULL);
|
||||
filter_rule_list_free(list);
|
||||
|
||||
unlink(path);
|
||||
rmdir(tmpl);
|
||||
}
|
||||
|
||||
static void test_filter_rule_parse_rejects_unsupported_and_keeps_supported() {
|
||||
char err[256] = "";
|
||||
|
||||
EXPECT_NULL(filter_rule_parse("-x user.foo", NULL, err, sizeof(err)));
|
||||
EXPECT_TRUE(strstr(err, "xattr") != NULL);
|
||||
|
||||
EXPECT_NULL(filter_rule_parse("-e foo", NULL, err, sizeof(err)));
|
||||
EXPECT_TRUE(strstr(err, "unsupported filter modifier") != NULL);
|
||||
|
||||
FilterRule* rule = filter_rule_parse("- *.tmp", NULL, err, sizeof(err));
|
||||
EXPECT_NOT_NULL(rule);
|
||||
EXPECT_EQ_STR(rule->pattern, "*.tmp");
|
||||
filter_rule_free(rule);
|
||||
|
||||
rule = filter_rule_parse("-newfile", NULL, err, sizeof(err));
|
||||
EXPECT_NOT_NULL(rule);
|
||||
EXPECT_EQ_STR(rule->pattern, "newfile");
|
||||
filter_rule_free(rule);
|
||||
}
|
||||
|
||||
static void test_filter_rules_apply_supported_modifiers() {
|
||||
/* exclude */
|
||||
{
|
||||
const char* texts[] = {"- *.tmp"};
|
||||
FilterRuleList* list = filter_base_build(texts, 1, false, false, NULL, 0);
|
||||
EXPECT_NOT_NULL(list);
|
||||
EXPECT_EQ_INT(filter_rules_apply(list, "b.tmp", "b.tmp", false), FILTER_ACTION_EXCLUDE);
|
||||
EXPECT_EQ_INT(filter_rules_apply(list, "a.txt", "a.txt", false), FILTER_ACTION_NONE);
|
||||
filter_rule_list_free(list);
|
||||
}
|
||||
/* anchored include then exclude-all */
|
||||
{
|
||||
const char* texts[] = {"+ /a.txt", "- *"};
|
||||
FilterRuleList* list = filter_base_build(texts, 2, false, false, NULL, 0);
|
||||
EXPECT_NOT_NULL(list);
|
||||
EXPECT_EQ_INT(filter_rules_apply(list, "a.txt", "a.txt", false), FILTER_ACTION_INCLUDE);
|
||||
EXPECT_EQ_INT(filter_rules_apply(list, "b.txt", "b.txt", false), FILTER_ACTION_EXCLUDE);
|
||||
filter_rule_list_free(list);
|
||||
}
|
||||
/* negate */
|
||||
{
|
||||
const char* texts[] = {"-! *.o"};
|
||||
FilterRuleList* list = filter_base_build(texts, 1, false, false, NULL, 0);
|
||||
EXPECT_NOT_NULL(list);
|
||||
EXPECT_EQ_INT(filter_rules_apply(list, "foo.c", "foo.c", false), FILTER_ACTION_EXCLUDE);
|
||||
EXPECT_EQ_INT(filter_rules_apply(list, "foo.o", "foo.o", false), FILTER_ACTION_NONE);
|
||||
filter_rule_list_free(list);
|
||||
}
|
||||
/* dir-only trailing slash */
|
||||
{
|
||||
const char* texts[] = {"+ dir/", "- *"};
|
||||
FilterRuleList* list = filter_base_build(texts, 2, false, false, NULL, 0);
|
||||
EXPECT_NOT_NULL(list);
|
||||
EXPECT_EQ_INT(filter_rules_apply(list, "dir", "dir", true), FILTER_ACTION_INCLUDE);
|
||||
EXPECT_EQ_INT(filter_rules_apply(list, "dir", "dir", false), FILTER_ACTION_EXCLUDE);
|
||||
filter_rule_list_free(list);
|
||||
}
|
||||
}
|
||||
|
||||
void test_filter() {
|
||||
test_filter_list_rejects_xattr_modifier();
|
||||
test_filter_list_rejects_unsupported_modifiers();
|
||||
test_filter_list_accepts_supported_rules_and_modifiers();
|
||||
test_filter_list_merge_file_still_supported();
|
||||
test_filter_rule_parse_rejects_unsupported_and_keeps_supported();
|
||||
test_filter_rules_apply_supported_modifiers();
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
#ifndef TEST_FILTER_H
|
||||
#define TEST_FILTER_H
|
||||
|
||||
void test_filter(void);
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user