Excludes: During directory traversal, use QRegularExpression

On Mac, this halves the time spent in csync_excluded_traversal
when using check_csync_excluded_performance. A similar performance
increase is seen on linux.
This commit is contained in:
Markus Goetz 2017-09-26 12:28:12 +02:00
parent 57cbba81e7
commit 3a1a56c7ad
7 changed files with 316 additions and 44 deletions

View file

@ -39,6 +39,8 @@
#include "common/utility.h"
#include <QString>
#ifdef _WIN32
#include <io.h>
#else
@ -234,20 +236,28 @@ static CSYNC_EXCLUDE_TYPE _csync_excluded_common(c_strlist_t *excludes, const ch
}
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.
@ -303,12 +313,6 @@ static CSYNC_EXCLUDE_TYPE _csync_excluded_common(c_strlist_t *excludes, const ch
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;
@ -415,8 +419,90 @@ static CSYNC_EXCLUDE_TYPE _csync_excluded_common(c_strlist_t *excludes, const ch
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) {

View file

@ -51,6 +51,15 @@ int OCSYNC_EXPORT _csync_exclude_add(c_strlist_t **inList, const char *string);
*/
int OCSYNC_EXPORT csync_exclude_load(const char *fname, c_strlist_t **list);
/**
* @brief When all list loads and list are done
*
* Used to initialize internal data structures that build upon the loaded excludes.
*
* @param ctx
*/
void OCSYNC_EXPORT csync_exclude_traversal_prepare(CSYNC *ctx);
/**
* @brief Check if the given path should be excluded in a traversal situation.
*
@ -66,10 +75,11 @@ int OCSYNC_EXPORT csync_exclude_load(const char *fname, c_strlist_t **list);
*
* @return 2 if excluded and needs cleanup, 1 if excluded, 0 if not.
*/
CSYNC_EXCLUDE_TYPE csync_excluded_traversal(c_strlist_t *excludes, const char *path, int filetype);
CSYNC_EXCLUDE_TYPE OCSYNC_EXPORT csync_excluded_traversal(CSYNC *ctx, const char *path, int filetype);
/**
* @brief csync_excluded_no_ctx
* @brief Checks all path components if the whole path should be excluded
*
* @param excludes
* @param path
* @param filetype

View file

@ -48,6 +48,8 @@
#include "csync_macros.h"
#include <QRegularExpression>
/**
* How deep to scan directories.
*/
@ -137,10 +139,21 @@ struct OCSYNC_EXPORT csync_s {
void *checksum_userdata = nullptr;
} callbacks;
c_strlist_t *excludes = nullptr;
OCC::SyncJournalDb *statedb;
c_strlist_t *excludes = nullptr; /* list of individual patterns collected from all exclude files */
struct TraversalExcludes {
~TraversalExcludes() {
c_strlist_destroy(list_patterns_fnmatch);
}
void prepare(c_strlist_t *excludes);
QRegularExpression regexp_exclude;
c_strlist_t *list_patterns_fnmatch = nullptr;
} parsed_traversal_excludes;
struct {
std::unordered_map<ByteArrayRef, QByteArray, ByteArrayRefHash> folder_renamed_to; // map from->to
std::unordered_map<ByteArrayRef, QByteArray, ByteArrayRefHash> folder_renamed_from; // map to->from

View file

@ -119,7 +119,7 @@ static int _csync_detect_update(CSYNC *ctx, std::unique_ptr<csync_file_stat_t> f
excluded =CSYNC_FILE_EXCLUDE_STAT_FAILED;
} else {
/* Check if file is excluded */
excluded = csync_excluded_traversal(ctx->excludes, fs->path, fs->type);
excluded = csync_excluded_traversal(ctx, fs->path, fs->type);
}
if( excluded == CSYNC_NOT_EXCLUDED ) {
@ -464,7 +464,7 @@ static bool fill_tree_from_db(CSYNC *ctx, const char *uri)
/* Check for exclusion from the tree.
* Note that this is only a safety net in case the ignore list changes
* without a full remote discovery being triggered. */
CSYNC_EXCLUDE_TYPE excluded = csync_excluded_traversal(ctx->excludes, st->path, st->type);
CSYNC_EXCLUDE_TYPE excluded = csync_excluded_traversal(ctx, st->path, st->type);
if (excluded != CSYNC_NOT_EXCLUDED) {
qDebug(lcUpdate, "%s excluded (%d)", st->path.constData(), excluded);

View file

@ -20,6 +20,7 @@
#include <csync_private.h>
#include <csync_rename.h>
#include <csync_exclude.h>
#include <QLoggingCategory>
#include <QUrl>
@ -718,6 +719,8 @@ void DiscoveryJob::start()
_csync_ctx->callbacks.remote_closedir_hook = remote_vio_closedir_hook;
_csync_ctx->callbacks.vio_userdata = this;
csync_exclude_traversal_prepare(_csync_ctx); // Converts the flat exclude list to optimized regexps
csync_set_log_callback(_log_callback);
csync_set_log_level(_log_level);
_lastUpdateProgressCallbackCall.invalidate();

View file

@ -63,6 +63,7 @@ bool ExcludedFiles::reloadExcludes()
if (csync_exclude_load(file.toUtf8(), _excludesPtr) < 0)
success = false;
}
// The csync_exclude_traversal_prepare is called implicitely at sync start.
return success;
}

View file

@ -59,6 +59,8 @@ static int setup_init(void **state) {
rc = _csync_exclude_add(&(csync->excludes), "latex/*/*.tex.tmp");
assert_int_equal(rc, 0);
csync_exclude_traversal_prepare(csync);
*state = csync;
return 0;
}
@ -98,6 +100,10 @@ static void check_csync_exclude_load(void **state)
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)
@ -110,6 +116,9 @@ 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);
@ -218,6 +227,16 @@ static void check_csync_excluded(void **state)
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)
@ -225,49 +244,188 @@ static void check_csync_excluded_traversal(void **state)
CSYNC *csync = (CSYNC*)*state;
int rc;
_csync_exclude_add( &(csync->excludes), "/exclude" );
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);
/* 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, "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);
rc = csync_excluded_traversal(csync->excludes, "/foo/exclude", CSYNC_FTW_TYPE_DIR);
/*
* 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, "/exclude", CSYNC_FTW_TYPE_DIR);
assert_int_equal(rc, CSYNC_FILE_EXCLUDE_LIST);
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)
@ -338,6 +496,7 @@ static void check_csync_is_windows_reserved_word(void **) {
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;
@ -370,8 +529,8 @@ static void check_csync_excluded_performance(void **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