mirror of
https://github.com/amadvance/snapraid.git
synced 2026-10-26 19:01:57 -04:00
Fix literal caret handling in Windows path normalization and wildcard matching
This commit is contained in:
parent
69a459ee43
commit
4fdfc8a923
4 changed files with 130 additions and 23 deletions
|
|
@ -864,6 +864,25 @@ struct {
|
|||
{ "Movies*", "Movies4/file.mkv", 0, 1 },
|
||||
|
||||
/* escaping of wildcard metacharacters */
|
||||
#ifdef _WIN32
|
||||
{ "foo^*bar", "foo*bar", 0, 0 },
|
||||
{ "foo^?bar", "foo?bar", 0, 0 },
|
||||
{ "foo^[bar", "foo[bar", 0, 0 },
|
||||
{ "foo^]bar", "foo]bar", 0, 0 },
|
||||
{ "foo^^bar", "foo^bar", 0, 0 },
|
||||
{ "foo^*bar", "fooXXXbar", 0, 1 },
|
||||
{ "foo^?bar", "fooXbar", 0, 1 },
|
||||
{ "foo^[bar", "fooXbar", 0, 1 },
|
||||
{ "foo^]bar", "fooXbar", 0, 1 },
|
||||
{ "foo*bar", "fooXXXbar", 0, 0 },
|
||||
{ "foo?bar", "fooXbar", 0, 0 },
|
||||
{ "foo[abc]bar", "fooabar", 0, 0 },
|
||||
{ "foo^abar", "foo^abar", 0, 0 },
|
||||
{ "foo^abar", "fooabar", 0, 1 },
|
||||
{ "foo^", "foo^", 0, 0 },
|
||||
{ "foo^", "foo", 0, 1 },
|
||||
{ "foo^bar", "foo^bar", 0, 0 },
|
||||
#else
|
||||
{ "foo\\*bar", "foo*bar", 0, 0 },
|
||||
{ "foo\\?bar", "foo?bar", 0, 0 },
|
||||
{ "foo\\[bar", "foo[bar", 0, 0 },
|
||||
|
|
@ -880,6 +899,8 @@ struct {
|
|||
{ "foo\\abar", "fooabar", 0, 1 },
|
||||
{ "foo\\", "foo\\", 0, 0 },
|
||||
{ "foo\\", "foo", 0, 1 },
|
||||
{ "foo^bar", "foo^bar", 0, 0 },
|
||||
#endif
|
||||
|
||||
{ 0 }
|
||||
};
|
||||
|
|
@ -896,6 +917,82 @@ static void test_wnmatch(void)
|
|||
}
|
||||
}
|
||||
|
||||
static void test_path(void)
|
||||
{
|
||||
char dst[PATH_MAX];
|
||||
|
||||
/*
|
||||
* Use strcmp instead of pathcmp because pathcmp on Windows treats
|
||||
* '/' and '\' as equivalent, which would prevent detecting bugs in
|
||||
* separator conversion by pathimport/pathexport.
|
||||
*/
|
||||
#ifdef _WIN32
|
||||
pathimport(dst, sizeof(dst), "foo\\bar");
|
||||
if (strcmp(dst, "foo/bar") != 0) {
|
||||
/* LCOV_EXCL_START */
|
||||
log_fatal(EINTERNAL, "Failed pathimport Windows separator test\n");
|
||||
exit(EXIT_FAILURE);
|
||||
/* LCOV_EXCL_STOP */
|
||||
}
|
||||
|
||||
pathimport(dst, sizeof(dst), "foo^bar");
|
||||
if (strcmp(dst, "foo^bar") != 0) {
|
||||
/* LCOV_EXCL_START */
|
||||
log_fatal(EINTERNAL, "Failed pathimport Windows caret test\n");
|
||||
exit(EXIT_FAILURE);
|
||||
/* LCOV_EXCL_STOP */
|
||||
}
|
||||
|
||||
pathexport(dst, sizeof(dst), "foo/bar");
|
||||
if (strcmp(dst, "foo\\bar") != 0) {
|
||||
/* LCOV_EXCL_START */
|
||||
log_fatal(EINTERNAL, "Failed pathexport Windows separator test\n");
|
||||
exit(EXIT_FAILURE);
|
||||
/* LCOV_EXCL_STOP */
|
||||
}
|
||||
|
||||
pathexport(dst, sizeof(dst), "foo^bar");
|
||||
if (strcmp(dst, "foo^bar") != 0) {
|
||||
/* LCOV_EXCL_START */
|
||||
log_fatal(EINTERNAL, "Failed pathexport Windows caret test\n");
|
||||
exit(EXIT_FAILURE);
|
||||
/* LCOV_EXCL_STOP */
|
||||
}
|
||||
#else
|
||||
pathimport(dst, sizeof(dst), "foo/bar");
|
||||
if (strcmp(dst, "foo/bar") != 0) {
|
||||
/* LCOV_EXCL_START */
|
||||
log_fatal(EINTERNAL, "Failed pathimport Unix test\n");
|
||||
exit(EXIT_FAILURE);
|
||||
/* LCOV_EXCL_STOP */
|
||||
}
|
||||
|
||||
pathimport(dst, sizeof(dst), "foo^bar");
|
||||
if (strcmp(dst, "foo^bar") != 0) {
|
||||
/* LCOV_EXCL_START */
|
||||
log_fatal(EINTERNAL, "Failed pathimport Unix caret test\n");
|
||||
exit(EXIT_FAILURE);
|
||||
/* LCOV_EXCL_STOP */
|
||||
}
|
||||
|
||||
pathexport(dst, sizeof(dst), "foo/bar");
|
||||
if (strcmp(dst, "foo/bar") != 0) {
|
||||
/* LCOV_EXCL_START */
|
||||
log_fatal(EINTERNAL, "Failed pathexport Unix test\n");
|
||||
exit(EXIT_FAILURE);
|
||||
/* LCOV_EXCL_STOP */
|
||||
}
|
||||
|
||||
pathexport(dst, sizeof(dst), "foo^bar");
|
||||
if (strcmp(dst, "foo^bar") != 0) {
|
||||
/* LCOV_EXCL_START */
|
||||
log_fatal(EINTERNAL, "Failed pathexport Unix caret test\n");
|
||||
exit(EXIT_FAILURE);
|
||||
/* LCOV_EXCL_STOP */
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
struct {
|
||||
const char* pattern;
|
||||
int valid;
|
||||
|
|
@ -1215,6 +1312,21 @@ static const struct filter_scenario FILTER_SCENARIOS[] = {
|
|||
{ "d1", "src/app.css", -1, 0, -1 },
|
||||
{ 0 }
|
||||
}
|
||||
},
|
||||
{
|
||||
"filter with literal caret in pattern and root",
|
||||
{
|
||||
{ 1, 0, "", "/foo^bar" },
|
||||
{ -1, 0, "proj^ect/sub/", "*.tmp" },
|
||||
{ 0 }
|
||||
},
|
||||
{
|
||||
{ "d1", "foo^bar", 0, 0, 0 },
|
||||
{ "d1", "foo_bar", 0, 0, 0 },
|
||||
{ "d1", "proj^ect/sub/file.tmp", -1, 0, 0 },
|
||||
{ "d1", "proj^ect/sub/file.txt", 0, 0, 0 },
|
||||
{ 0 }
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -1564,6 +1676,9 @@ void selftest(void)
|
|||
/* filter pattern parsing */
|
||||
test_filter();
|
||||
|
||||
/* pathname import and export */
|
||||
test_path();
|
||||
|
||||
/* smartctl output parsing */
|
||||
test_parse_smartctl();
|
||||
|
||||
|
|
|
|||
|
|
@ -366,7 +366,11 @@ static inline int is_wild_escape(char c)
|
|||
|| c == '?'
|
||||
|| c == '['
|
||||
|| c == ']'
|
||||
#ifdef _WIN32
|
||||
|| c == '^';
|
||||
#else
|
||||
|| c == '\\';
|
||||
#endif
|
||||
}
|
||||
|
||||
int wnmatch_sub(const char* p, const char* t, int match_sub)
|
||||
|
|
@ -375,13 +379,16 @@ int wnmatch_sub(const char* p, const char* t, int match_sub)
|
|||
while (*p) {
|
||||
char p0 = *p;
|
||||
switch (p0) {
|
||||
#ifdef _WIN32
|
||||
case '^' :
|
||||
#else
|
||||
case '\\' :
|
||||
#endif
|
||||
/*
|
||||
* Escape wildcard metacharacters.
|
||||
*
|
||||
* '\' is the canonical internal escape character.
|
||||
* On Windows, pathimport() converts the external '^'
|
||||
* escape syntax to this form before matching.
|
||||
* If the following character is not escapable, the
|
||||
* escape character itself is matched literally.
|
||||
*/
|
||||
if (is_wild_escape(p[1]))
|
||||
++p;
|
||||
|
|
|
|||
|
|
@ -127,7 +127,7 @@ unsigned strtou(const char* nptr, char** endptr, int base);
|
|||
* - ** (not near a /) like *
|
||||
* - ##/ reduces to nothing in addition to the normal matching of ** (using # instead of * to not mess the C comment)
|
||||
* - [...] matches character classes with support for ranges and negation lile [!...] or [^...], except /
|
||||
* - \ escapes *, ?, [, ], and \
|
||||
* - \ (Unix) or ^ (Windows) escapes *, ?, [, ], and the escape character itself
|
||||
*
|
||||
* \return 0 if it matches
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -1094,19 +1094,10 @@ void pathimport(char* dst, size_t size, const char* src)
|
|||
pathcpy(dst, size, src);
|
||||
|
||||
#ifdef _WIN32
|
||||
/*
|
||||
* Convert the Windows dir separator '\' to C '/',
|
||||
* and the Windows escaping char '^' to the fnmatch '\'
|
||||
*/
|
||||
/* Convert the Windows dir separator '\' to C '/' */
|
||||
while (*dst) {
|
||||
switch (*dst) {
|
||||
case '\\' :
|
||||
if (*dst == '\\')
|
||||
*dst = '/';
|
||||
break;
|
||||
case '^' :
|
||||
*dst = '\\';
|
||||
break;
|
||||
}
|
||||
++dst;
|
||||
}
|
||||
#endif
|
||||
|
|
@ -1117,16 +1108,10 @@ void pathexport(char* dst, size_t size, const char* src)
|
|||
pathcpy(dst, size, src);
|
||||
|
||||
#ifdef _WIN32
|
||||
/* invert the import */
|
||||
/* Convert C '/' to Windows dir separator '\' */
|
||||
while (*dst) {
|
||||
switch (*dst) {
|
||||
case '/' :
|
||||
if (*dst == '/')
|
||||
*dst = '\\';
|
||||
break;
|
||||
case '\\' :
|
||||
*dst = '^';
|
||||
break;
|
||||
}
|
||||
++dst;
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue