#include "common/utility.h"
+#include <QString>
+
#ifdef _WIN32
#include <io.h>
#else
}
blen = strlen(bname);
- rc = csync_fnmatch("._sync_*.db*", bname, 0);
- if (rc == 0) {
- match = CSYNC_FILE_SILENTLY_EXCLUDED;
- goto out;
- }
- rc = csync_fnmatch(".sync_*.db*", bname, 0);
- if (rc == 0) {
- match = CSYNC_FILE_SILENTLY_EXCLUDED;
- goto out;
- }
- rc = csync_fnmatch(".csync_journal.db*", bname, 0);
- if (rc == 0) {
- match = CSYNC_FILE_SILENTLY_EXCLUDED;
- goto out;
+ // 9 = strlen(".sync_.db")
+ if (blen >= 9 && bname[0] == '.') {
+ rc = csync_fnmatch("._sync_*.db*", bname, 0);
+ if (rc == 0) {
+ match = CSYNC_FILE_SILENTLY_EXCLUDED;
+ goto out;
+ }
+ rc = csync_fnmatch(".sync_*.db*", bname, 0);
+ if (rc == 0) {
+ match = CSYNC_FILE_SILENTLY_EXCLUDED;
+ goto out;
+ }
+ rc = csync_fnmatch(".csync_journal.db*", bname, 0);
+ if (rc == 0) {
+ match = CSYNC_FILE_SILENTLY_EXCLUDED;
+ goto out;
+ }
+ rc = csync_fnmatch(".owncloudsync.log*", bname, 0);
+ if (rc == 0) {
+ match = CSYNC_FILE_SILENTLY_EXCLUDED;
+ goto out;
+ }
}
// check the strlen and ignore the file if its name is longer than 254 chars.
goto out;
}
- rc = csync_fnmatch(".owncloudsync.log*", bname, 0);
- if (rc == 0) {
- match = CSYNC_FILE_SILENTLY_EXCLUDED;
- goto out;
- }
-
if (!OCC::Utility::shouldUploadConflictFiles()) {
if (OCC::Utility::isConflictFile(bname)) {
match = CSYNC_FILE_EXCLUDE_CONFLICT;
return match;
}
-CSYNC_EXCLUDE_TYPE csync_excluded_traversal(c_strlist_t *excludes, const char *path, int filetype) {
- return _csync_excluded_common(excludes, path, filetype, false);
+/* Only for bnames (not paths) */
+static QString convertToBnameRegexpSyntax(QString exclude)
+{
+ QString s = QRegularExpression::escape(exclude).replace("\\*", ".*").replace("\\?", ".");
+ return s;
+}
+
+void csync_exclude_traversal_prepare(CSYNC *ctx)
+{
+ ctx->parsed_traversal_excludes.prepare(ctx->excludes);
+}
+
+void csync_s::TraversalExcludes::prepare(c_strlist_t *excludes)
+{
+ c_strlist_destroy(list_patterns_fnmatch);
+ list_patterns_fnmatch = nullptr;
+
+ // Start out with regexes that would match nothing
+ QString exclude_only = "a^";
+ QString exclude_and_remove = "a^";
+
+ size_t exclude_count = excludes ? excludes->count : 0;
+ for (unsigned int i = 0; i < exclude_count; i++) {
+ char *exclude = excludes->vector[i];
+ QString *builderToUse = & exclude_only;
+ if (exclude[0] == '\n') continue; // empty line
+ if (exclude[0] == '\r') continue; // empty line
+
+ /* If an exclude entry contains some fnmatch-ish characters, we use the C-style codepath without QRegularEpression */
+ if (strchr(exclude, '/') || strchr(exclude, '[') || strchr(exclude, '{')) {
+ _csync_exclude_add(&list_patterns_fnmatch, exclude);
+ continue;
+ }
+
+ /* Those will attempt to use QRegularExpression */
+ if (exclude[0] == ']'){
+ exclude++;
+ builderToUse = &exclude_and_remove;
+ }
+ if (builderToUse->size() > 0) {
+ builderToUse->append("|");
+ }
+ builderToUse->append(convertToBnameRegexpSyntax(exclude));
+ }
+
+ QString pattern = "^(" + exclude_only + ")$|^(" + exclude_and_remove + ")$";
+ regexp_exclude.setPattern(pattern);
+ QRegularExpression::PatternOptions patternOptions = QRegularExpression::OptimizeOnFirstUsageOption;
+ if (OCC::Utility::fsCasePreserving())
+ patternOptions |= QRegularExpression::CaseInsensitiveOption;
+ regexp_exclude.setPatternOptions(patternOptions);
+ regexp_exclude.optimize();
+}
+
+CSYNC_EXCLUDE_TYPE csync_excluded_traversal(CSYNC *ctx, const char *path, int filetype) {
+ CSYNC_EXCLUDE_TYPE match = CSYNC_NOT_EXCLUDED;
+
+ /* Check only static patterns and only with the reduced list which is empty usually */
+ match = _csync_excluded_common(ctx->parsed_traversal_excludes.list_patterns_fnmatch, path, filetype, false);
+ if (match != CSYNC_NOT_EXCLUDED) {
+ return match;
+ }
+
+ if (ctx->excludes) {
+ /* Now check with our optimized regexps */
+ const char *bname = NULL;
+ /* split up the path */
+ bname = strrchr(path, '/');
+ if (bname) {
+ bname += 1; // don't include the /
+ } else {
+ bname = path;
+ }
+ QString p = QString::fromUtf8(bname);
+ auto m = ctx->parsed_traversal_excludes.regexp_exclude.match(p);
+ if (m.hasMatch()) {
+ if (!m.captured(1).isEmpty()) {
+ match = CSYNC_FILE_EXCLUDE_LIST;
+ } else if (!m.captured(2).isEmpty()) {
+ match = CSYNC_FILE_EXCLUDE_AND_REMOVE;
+ }
+ }
+ }
+ return match;
}
CSYNC_EXCLUDE_TYPE csync_excluded_no_ctx(c_strlist_t *excludes, const char *path, int filetype) {
rc = _csync_exclude_add(&(csync->excludes), "latex/*/*.tex.tmp");
assert_int_equal(rc, 0);
+ csync_exclude_traversal_prepare(csync);
+
*state = csync;
return 0;
}
assert_string_equal(csync->excludes->vector[0], "*~");
assert_int_not_equal(csync->excludes->count, 0);
+
+ assert_true(csync->parsed_traversal_excludes.regexp_exclude.pattern().isEmpty());
+ csync_exclude_traversal_prepare(csync); /* parse into regular expression */
+ assert_false(csync->parsed_traversal_excludes.regexp_exclude.pattern().isEmpty());
}
static void check_csync_excluded(void **state)
rc = csync_excluded_no_ctx(csync->excludes, "/", CSYNC_FTW_TYPE_FILE);
assert_int_equal(rc, CSYNC_NOT_EXCLUDED);
+ rc = csync_excluded_no_ctx(csync->excludes, "A", CSYNC_FTW_TYPE_FILE);
+ assert_int_equal(rc, CSYNC_NOT_EXCLUDED);
+
rc = csync_excluded_no_ctx(csync->excludes, "krawel_krawel", CSYNC_FTW_TYPE_FILE);
assert_int_equal(rc, CSYNC_NOT_EXCLUDED);
rc = csync_excluded_no_ctx(csync->excludes, ".kde/share/config/kwin.eventsrc", CSYNC_FTW_TYPE_FILE);
rc = csync_excluded_no_ctx(csync->excludes, "file_invalid_char<", CSYNC_FTW_TYPE_FILE);
assert_int_equal(rc, CSYNC_FILE_EXCLUDE_INVALID_CHAR);
#endif
+
+ /* ? character */
+ _csync_exclude_add( &(csync->excludes), "bond00?" );
+ csync_exclude_traversal_prepare(csync);
+ rc = csync_excluded_no_ctx(csync->excludes, "bond00", CSYNC_FTW_TYPE_FILE);
+ assert_int_equal(rc, CSYNC_NOT_EXCLUDED);
+ rc = csync_excluded_no_ctx(csync->excludes, "bond007", CSYNC_FTW_TYPE_FILE);
+ assert_int_equal(rc, CSYNC_FILE_EXCLUDE_LIST);
+ rc = csync_excluded_no_ctx(csync->excludes, "bond0071", CSYNC_FTW_TYPE_FILE);
+ assert_int_equal(rc, CSYNC_NOT_EXCLUDED);
}
static void check_csync_excluded_traversal(void **state)
CSYNC *csync = (CSYNC*)*state;
int rc;
+ rc = csync_excluded_traversal(csync, "", CSYNC_FTW_TYPE_FILE);
+ assert_int_equal(rc, CSYNC_NOT_EXCLUDED);
+ rc = csync_excluded_traversal(csync, "/", CSYNC_FTW_TYPE_FILE);
+ assert_int_equal(rc, CSYNC_NOT_EXCLUDED);
+
+ rc = csync_excluded_traversal(csync, "A", CSYNC_FTW_TYPE_FILE);
+ assert_int_equal(rc, CSYNC_NOT_EXCLUDED);
+
+ rc = csync_excluded_traversal(csync, "krawel_krawel", CSYNC_FTW_TYPE_FILE);
+ assert_int_equal(rc, CSYNC_NOT_EXCLUDED);
+ rc = csync_excluded_traversal(csync, ".kde/share/config/kwin.eventsrc", CSYNC_FTW_TYPE_FILE);
+ assert_int_equal(rc, CSYNC_NOT_EXCLUDED);
+ rc = csync_excluded_traversal(csync, "mozilla/.directory", CSYNC_FTW_TYPE_DIR);
+ assert_int_equal(rc, CSYNC_FILE_EXCLUDE_LIST);
+
+ /*
+ * Test for patterns in subdirs. '.beagle' is defined as a pattern and has
+ * to be found in top dir as well as in directories underneath.
+ */
+ rc = csync_excluded_traversal(csync, ".apdisk", CSYNC_FTW_TYPE_DIR);
+ assert_int_equal(rc, CSYNC_FILE_EXCLUDE_LIST);
+ rc = csync_excluded_traversal(csync, "foo/.apdisk", CSYNC_FTW_TYPE_DIR);
+ assert_int_equal(rc, CSYNC_FILE_EXCLUDE_LIST);
+ rc = csync_excluded_traversal(csync, "foo/bar/.apdisk", CSYNC_FTW_TYPE_DIR);
+ assert_int_equal(rc, CSYNC_FILE_EXCLUDE_LIST);
+
+ rc = csync_excluded_traversal(csync, ".java", CSYNC_FTW_TYPE_FILE);
+ assert_int_equal(rc, CSYNC_NOT_EXCLUDED);
+
+ /* csync-journal is ignored in general silently. */
+ rc = csync_excluded_traversal(csync, ".csync_journal.db", CSYNC_FTW_TYPE_FILE);
+ assert_int_equal(rc, CSYNC_FILE_SILENTLY_EXCLUDED);
+ rc = csync_excluded_traversal(csync, ".csync_journal.db.ctmp", CSYNC_FTW_TYPE_FILE);
+ assert_int_equal(rc, CSYNC_FILE_SILENTLY_EXCLUDED);
+ rc = csync_excluded_traversal(csync, "subdir/.csync_journal.db", CSYNC_FTW_TYPE_FILE);
+ assert_int_equal(rc, CSYNC_FILE_SILENTLY_EXCLUDED);
+ rc = csync_excluded_traversal(csync, "/two/subdir/.csync_journal.db", CSYNC_FTW_TYPE_FILE);
+ assert_int_equal(rc, CSYNC_FILE_SILENTLY_EXCLUDED);
+
+ /* also the new form of the database name */
+ rc = csync_excluded_traversal(csync, "._sync_5bdd60bdfcfa.db", CSYNC_FTW_TYPE_FILE);
+ assert_int_equal(rc, CSYNC_FILE_SILENTLY_EXCLUDED);
+ rc = csync_excluded_traversal(csync, "._sync_5bdd60bdfcfa.db.ctmp", CSYNC_FTW_TYPE_FILE);
+ assert_int_equal(rc, CSYNC_FILE_SILENTLY_EXCLUDED);
+ rc = csync_excluded_traversal(csync, "._sync_5bdd60bdfcfa.db-shm", CSYNC_FTW_TYPE_FILE);
+ assert_int_equal(rc, CSYNC_FILE_SILENTLY_EXCLUDED);
+ rc = csync_excluded_traversal(csync, "subdir/._sync_5bdd60bdfcfa.db", CSYNC_FTW_TYPE_FILE);
+ assert_int_equal(rc, CSYNC_FILE_SILENTLY_EXCLUDED);
+
+ rc = csync_excluded_traversal(csync, ".sync_5bdd60bdfcfa.db", CSYNC_FTW_TYPE_FILE);
+ assert_int_equal(rc, CSYNC_FILE_SILENTLY_EXCLUDED);
+ rc = csync_excluded_traversal(csync, ".sync_5bdd60bdfcfa.db.ctmp", CSYNC_FTW_TYPE_FILE);
+ assert_int_equal(rc, CSYNC_FILE_SILENTLY_EXCLUDED);
+ rc = csync_excluded_traversal(csync, ".sync_5bdd60bdfcfa.db-shm", CSYNC_FTW_TYPE_FILE);
+ assert_int_equal(rc, CSYNC_FILE_SILENTLY_EXCLUDED);
+ rc = csync_excluded_traversal(csync, "subdir/.sync_5bdd60bdfcfa.db", CSYNC_FTW_TYPE_FILE);
+ assert_int_equal(rc, CSYNC_FILE_SILENTLY_EXCLUDED);
+
+
+ /* pattern ]*.directory - ignore and remove */
+ rc = csync_excluded_traversal(csync, "my.~directory", CSYNC_FTW_TYPE_FILE);
+ assert_int_equal(rc, CSYNC_FILE_EXCLUDE_AND_REMOVE);
+
+ rc = csync_excluded_traversal(csync, "/a_folder/my.~directory", CSYNC_FTW_TYPE_FILE);
+ assert_int_equal(rc, CSYNC_FILE_EXCLUDE_AND_REMOVE);
+
+ /* Not excluded because the pattern .netscape/cache requires directory. */
+ rc = csync_excluded_traversal(csync, ".netscape/cache", CSYNC_FTW_TYPE_FILE);
+ assert_int_equal(rc, CSYNC_NOT_EXCLUDED);
+
+ /* Not excluded */
+ rc = csync_excluded_traversal(csync, "unicode/中文.hé", CSYNC_FTW_TYPE_FILE);
+ assert_int_equal(rc, CSYNC_NOT_EXCLUDED);
+ /* excluded */
+ rc = csync_excluded_traversal(csync, "unicode/пятницы.txt", CSYNC_FTW_TYPE_FILE);
+ assert_int_equal(rc, CSYNC_FILE_EXCLUDE_LIST);
+ rc = csync_excluded_traversal(csync, "unicode/中文.💩", CSYNC_FTW_TYPE_FILE);
+ assert_int_equal(rc, CSYNC_FILE_EXCLUDE_LIST);
+
+ /* path wildcards */
+ rc = csync_excluded_traversal(csync, "foobar/my_manuscript.out", CSYNC_FTW_TYPE_FILE);
+ assert_int_equal(rc, CSYNC_FILE_EXCLUDE_LIST);
+
+ rc = csync_excluded_traversal(csync, "latex_tmp/my_manuscript.run.xml", CSYNC_FTW_TYPE_FILE);
+ assert_int_equal(rc, CSYNC_FILE_EXCLUDE_LIST);
+
+ rc = csync_excluded_traversal(csync, "word_tmp/my_manuscript.run.xml", CSYNC_FTW_TYPE_FILE);
+ assert_int_equal(rc, CSYNC_NOT_EXCLUDED);
+
+ rc = csync_excluded_traversal(csync, "latex/my_manuscript.tex.tmp", CSYNC_FTW_TYPE_FILE);
+ assert_int_equal(rc, CSYNC_NOT_EXCLUDED);
+
+ rc = csync_excluded_traversal(csync, "latex/songbook/my_manuscript.tex.tmp", CSYNC_FTW_TYPE_FILE);
+ assert_int_equal(rc, CSYNC_FILE_EXCLUDE_LIST);
+
+#ifdef _WIN32
+ rc = csync_excluded_traversal(csync, "file_trailing_space ", CSYNC_FTW_TYPE_FILE);
+ assert_int_equal(rc, CSYNC_FILE_EXCLUDE_TRAILING_SPACE);
+
+ rc = csync_excluded_traversal(csync, "file_trailing_dot.", CSYNC_FTW_TYPE_FILE);
+ assert_int_equal(rc, CSYNC_FILE_EXCLUDE_INVALID_CHAR);
+
+ rc = csync_excluded_traversal(csync, "AUX", CSYNC_FTW_TYPE_FILE);
+ assert_int_equal(rc, CSYNC_FILE_EXCLUDE_INVALID_CHAR);
+
+ rc = csync_excluded_traversal(csync, "file_invalid_char<", CSYNC_FTW_TYPE_FILE);
+ assert_int_equal(rc, CSYNC_FILE_EXCLUDE_INVALID_CHAR);
+#endif
+
+
+ /* From here the actual traversal tests */
+
_csync_exclude_add( &(csync->excludes), "/exclude" );
+ csync_exclude_traversal_prepare(csync);
/* Check toplevel dir, the pattern only works for toplevel dir. */
- rc = csync_excluded_traversal(csync->excludes, "/exclude", CSYNC_FTW_TYPE_DIR);
+ rc = csync_excluded_traversal(csync, "/exclude", CSYNC_FTW_TYPE_DIR);
assert_int_equal(rc, CSYNC_FILE_EXCLUDE_LIST);
- rc = csync_excluded_traversal(csync->excludes, "/foo/exclude", CSYNC_FTW_TYPE_DIR);
+ rc = csync_excluded_traversal(csync, "/foo/exclude", CSYNC_FTW_TYPE_DIR);
assert_int_equal(rc, CSYNC_NOT_EXCLUDED);
/* check for a file called exclude. Must still work */
- rc = csync_excluded_traversal(csync->excludes, "/exclude", CSYNC_FTW_TYPE_FILE);
+ rc = csync_excluded_traversal(csync, "/exclude", CSYNC_FTW_TYPE_FILE);
assert_int_equal(rc, CSYNC_FILE_EXCLUDE_LIST);
- rc = csync_excluded_traversal(csync->excludes, "/foo/exclude", CSYNC_FTW_TYPE_FILE);
+ rc = csync_excluded_traversal(csync, "/foo/exclude", CSYNC_FTW_TYPE_FILE);
assert_int_equal(rc, CSYNC_NOT_EXCLUDED);
/* Add an exclude for directories only: excl/ */
_csync_exclude_add( &(csync->excludes), "excl/" );
- rc = csync_excluded_traversal(csync->excludes, "/excl", CSYNC_FTW_TYPE_DIR);
+ csync_exclude_traversal_prepare(csync);
+ rc = csync_excluded_traversal(csync, "/excl", CSYNC_FTW_TYPE_DIR);
assert_int_equal(rc, CSYNC_FILE_EXCLUDE_LIST);
- rc = csync_excluded_traversal(csync->excludes, "meep/excl", CSYNC_FTW_TYPE_DIR);
+ rc = csync_excluded_traversal(csync, "meep/excl", CSYNC_FTW_TYPE_DIR);
assert_int_equal(rc, CSYNC_FILE_EXCLUDE_LIST);
- rc = csync_excluded_traversal(csync->excludes, "meep/excl/file", CSYNC_FTW_TYPE_FILE);
+ rc = csync_excluded_traversal(csync, "meep/excl/file", CSYNC_FTW_TYPE_FILE);
assert_int_equal(rc, CSYNC_NOT_EXCLUDED); // because leading dirs aren't checked!
- rc = csync_excluded_traversal(csync->excludes, "/excl", CSYNC_FTW_TYPE_FILE);
+ rc = csync_excluded_traversal(csync, "/excl", CSYNC_FTW_TYPE_FILE);
assert_int_equal(rc, CSYNC_NOT_EXCLUDED);
_csync_exclude_add(&csync->excludes, "/excludepath/withsubdir");
+ csync_exclude_traversal_prepare(csync);
- rc = csync_excluded_traversal(csync->excludes, "/excludepath/withsubdir", CSYNC_FTW_TYPE_DIR);
+ rc = csync_excluded_traversal(csync, "/excludepath/withsubdir", CSYNC_FTW_TYPE_DIR);
assert_int_equal(rc, CSYNC_FILE_EXCLUDE_LIST);
- rc = csync_excluded_traversal(csync->excludes, "/excludepath/withsubdir", CSYNC_FTW_TYPE_FILE);
+ rc = csync_excluded_traversal(csync, "/excludepath/withsubdir", CSYNC_FTW_TYPE_FILE);
assert_int_equal(rc, CSYNC_FILE_EXCLUDE_LIST);
- rc = csync_excluded_traversal(csync->excludes, "/excludepath/withsubdir2", CSYNC_FTW_TYPE_DIR);
+ rc = csync_excluded_traversal(csync, "/excludepath/withsubdir2", CSYNC_FTW_TYPE_DIR);
assert_int_equal(rc, CSYNC_NOT_EXCLUDED);
- rc = csync_excluded_traversal(csync->excludes, "/excludepath/withsubdir/foo", CSYNC_FTW_TYPE_DIR);
+ rc = csync_excluded_traversal(csync, "/excludepath/withsubdir/foo", CSYNC_FTW_TYPE_DIR);
assert_int_equal(rc, CSYNC_NOT_EXCLUDED); // because leading dirs aren't checked!
+
+ /* Check ending of pattern */
+ rc = csync_excluded_traversal(csync, "/exclude", CSYNC_FTW_TYPE_FILE);
+ assert_int_equal(rc, CSYNC_FILE_EXCLUDE_LIST);
+ rc = csync_excluded_traversal(csync, "/excludeX", CSYNC_FTW_TYPE_FILE);
+ assert_int_equal(rc, CSYNC_NOT_EXCLUDED);
+ rc = csync_excluded_traversal(csync, "exclude", CSYNC_FTW_TYPE_FILE);
+ assert_int_equal(rc, CSYNC_NOT_EXCLUDED);
+
+ _csync_exclude_add( &(csync->excludes), "exclude" );
+ csync_exclude_traversal_prepare(csync);
+ rc = csync_excluded_traversal(csync, "exclude", CSYNC_FTW_TYPE_FILE);
+ assert_int_equal(rc, CSYNC_FILE_EXCLUDE_LIST);
+
+ /* ? character */
+ _csync_exclude_add( &(csync->excludes), "bond00?" );
+ csync_exclude_traversal_prepare(csync);
+ rc = csync_excluded_traversal(csync, "bond00", CSYNC_FTW_TYPE_FILE);
+ assert_int_equal(rc, CSYNC_NOT_EXCLUDED);
+ rc = csync_excluded_traversal(csync, "bond007", CSYNC_FTW_TYPE_FILE);
+ assert_int_equal(rc, CSYNC_FILE_EXCLUDE_LIST);
+ rc = csync_excluded_traversal(csync, "bond0071", CSYNC_FTW_TYPE_FILE);
+ assert_int_equal(rc, CSYNC_NOT_EXCLUDED);
+
}
static void check_csync_pathes(void **state)
assert_true(csync_is_windows_reserved_word("m:"));
}
+/* QT_ENABLE_REGEXP_JIT=0 to get slower results :-) */
static void check_csync_excluded_performance(void **state)
{
CSYNC *csync = (CSYNC*)*state;
gettimeofday(&before, 0);
for (i = 0; i < N; ++i) {
- totalRc += csync_excluded_traversal(csync->excludes, "/this/is/quite/a/long/path/with/many/components", CSYNC_FTW_TYPE_DIR);
- totalRc += csync_excluded_traversal(csync->excludes, "/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/29", CSYNC_FTW_TYPE_FILE);
+ totalRc += csync_excluded_traversal(csync, "/this/is/quite/a/long/path/with/many/components", CSYNC_FTW_TYPE_DIR);
+ totalRc += csync_excluded_traversal(csync, "/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/29", CSYNC_FTW_TYPE_FILE);
}
assert_int_equal(totalRc, CSYNC_NOT_EXCLUDED); // mainly to avoid optimization