check_csync_exclude.cpp 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721
  1. /*
  2. * libcsync -- a library to sync a directory with another
  3. *
  4. * Copyright (c) 2008-2013 by Andreas Schneider <asn@cryptomilk.org>
  5. *
  6. * This library is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU Lesser General Public
  8. * License as published by the Free Software Foundation; either
  9. * version 2.1 of the License, or (at your option) any later version.
  10. *
  11. * This library is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. * Lesser General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Lesser General Public
  17. * License along with this library; if not, write to the Free Software
  18. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  19. */
  20. #include "config_csync.h"
  21. #include <cstring>
  22. #include <ctime>
  23. #include <sys/time.h>
  24. #include <cstdio>
  25. #define CSYNC_TEST 1
  26. #include "csync_exclude.cpp"
  27. #include "torture.h"
  28. #define EXCLUDE_LIST_FILE SOURCEDIR"/../../sync-exclude.lst"
  29. ExcludedFiles *excludedFiles = nullptr;
  30. class ExcludedFilesTest
  31. {
  32. public:
  33. static int setup(void **state) {
  34. CSYNC *csync = nullptr;
  35. csync = new CSYNC("/tmp/check_csync1", new OCC::SyncJournalDb(""));
  36. excludedFiles = new ExcludedFiles;
  37. excludedFiles->setWildcardsMatchSlash(false);
  38. csync->exclude_traversal_fn = excludedFiles->csyncTraversalMatchFun();
  39. *state = csync;
  40. return 0;
  41. }
  42. static int setup_init(void **state) {
  43. CSYNC *csync = nullptr;
  44. csync = new CSYNC("/tmp/check_csync1", new OCC::SyncJournalDb(""));
  45. excludedFiles = new ExcludedFiles;
  46. excludedFiles->setWildcardsMatchSlash(false);
  47. csync->exclude_traversal_fn = excludedFiles->csyncTraversalMatchFun();
  48. excludedFiles->addExcludeFilePath(EXCLUDE_LIST_FILE);
  49. assert_true(excludedFiles->reloadExcludeFiles());
  50. /* and add some unicode stuff */
  51. excludedFiles->addManualExclude("*.💩"); // is this source file utf8 encoded?
  52. excludedFiles->addManualExclude("пятницы.*");
  53. excludedFiles->addManualExclude("*/*.out");
  54. excludedFiles->addManualExclude("latex*/*.run.xml");
  55. excludedFiles->addManualExclude("latex/*/*.tex.tmp");
  56. assert_true(excludedFiles->reloadExcludeFiles());
  57. *state = csync;
  58. return 0;
  59. }
  60. static int teardown(void **state) {
  61. CSYNC *csync = (CSYNC*)*state;
  62. int rc = 0;
  63. auto statedb = csync->statedb;
  64. delete csync;
  65. delete statedb;
  66. delete excludedFiles;
  67. rc = system("rm -rf /tmp/check_csync1");
  68. assert_int_equal(rc, 0);
  69. rc = system("rm -rf /tmp/check_csync2");
  70. assert_int_equal(rc, 0);
  71. *state = nullptr;
  72. return 0;
  73. }
  74. static int check_file_full(const char *path)
  75. {
  76. return excludedFiles->fullPatternMatch(path, ItemTypeFile);
  77. }
  78. static int check_dir_full(const char *path)
  79. {
  80. return excludedFiles->fullPatternMatch(path, ItemTypeDirectory);
  81. }
  82. static int check_file_traversal(const char *path)
  83. {
  84. return excludedFiles->traversalPatternMatch(path, ItemTypeFile);
  85. }
  86. static int check_dir_traversal(const char *path)
  87. {
  88. return excludedFiles->traversalPatternMatch(path, ItemTypeDirectory);
  89. }
  90. static void check_csync_exclude_add(void **)
  91. {
  92. excludedFiles->addManualExclude("/tmp/check_csync1/*");
  93. assert_int_equal(check_file_full("/tmp/check_csync1/foo"), CSYNC_FILE_EXCLUDE_LIST);
  94. assert_int_equal(check_file_full("/tmp/check_csync2/foo"), CSYNC_NOT_EXCLUDED);
  95. assert_true(excludedFiles->_allExcludes["/"].contains("/tmp/check_csync1/*"));
  96. assert_true(excludedFiles->_fullRegexFile["/"].pattern().contains("csync1"));
  97. assert_true(excludedFiles->_fullTraversalRegexFile["/"].pattern().contains("csync1"));
  98. assert_false(excludedFiles->_bnameTraversalRegexFile["/"].pattern().contains("csync1"));
  99. excludedFiles->addManualExclude("foo");
  100. assert_true(excludedFiles->_bnameTraversalRegexFile["/"].pattern().contains("foo"));
  101. assert_true(excludedFiles->_fullRegexFile["/"].pattern().contains("foo"));
  102. assert_false(excludedFiles->_fullTraversalRegexFile["/"].pattern().contains("foo"));
  103. }
  104. static void check_csync_exclude_add_per_dir(void **)
  105. {
  106. excludedFiles->addManualExclude("*", "/tmp/check_csync1/");
  107. assert_int_equal(check_file_full("/tmp/check_csync1/foo"), CSYNC_FILE_EXCLUDE_LIST);
  108. assert_int_equal(check_file_full("/tmp/check_csync2/foo"), CSYNC_NOT_EXCLUDED);
  109. assert_true(excludedFiles->_allExcludes["/tmp/check_csync1/"].contains("*"));
  110. excludedFiles->addManualExclude("foo");
  111. assert_true(excludedFiles->_fullRegexFile["/"].pattern().contains("foo"));
  112. excludedFiles->addManualExclude("foo/bar", "/tmp/check_csync1/");
  113. assert_true(excludedFiles->_fullRegexFile["/tmp/check_csync1/"].pattern().contains("bar"));
  114. assert_true(excludedFiles->_fullTraversalRegexFile["/tmp/check_csync1/"].pattern().contains("bar"));
  115. assert_false(excludedFiles->_bnameTraversalRegexFile["/tmp/check_csync1/"].pattern().contains("foo"));
  116. }
  117. static void check_csync_excluded(void **)
  118. {
  119. assert_int_equal(check_file_full(""), CSYNC_NOT_EXCLUDED);
  120. assert_int_equal(check_file_full("/"), CSYNC_NOT_EXCLUDED);
  121. assert_int_equal(check_file_full("A"), CSYNC_NOT_EXCLUDED);
  122. assert_int_equal(check_file_full("krawel_krawel"), CSYNC_NOT_EXCLUDED);
  123. assert_int_equal(check_file_full(".kde/share/config/kwin.eventsrc"), CSYNC_NOT_EXCLUDED);
  124. assert_int_equal(check_file_full(".directory/cache-maximegalon/cache1.txt"), CSYNC_FILE_EXCLUDE_LIST);
  125. assert_int_equal(check_dir_full("mozilla/.directory"), CSYNC_FILE_EXCLUDE_LIST);
  126. /*
  127. * Test for patterns in subdirs. '.beagle' is defined as a pattern and has
  128. * to be found in top dir as well as in directories underneath.
  129. */
  130. assert_int_equal(check_dir_full(".apdisk"), CSYNC_FILE_EXCLUDE_LIST);
  131. assert_int_equal(check_dir_full("foo/.apdisk"), CSYNC_FILE_EXCLUDE_LIST);
  132. assert_int_equal(check_dir_full("foo/bar/.apdisk"), CSYNC_FILE_EXCLUDE_LIST);
  133. assert_int_equal(check_file_full(".java"), CSYNC_NOT_EXCLUDED);
  134. /* Files in the ignored dir .java will also be ignored. */
  135. assert_int_equal(check_file_full(".apdisk/totally_amazing.jar"), CSYNC_FILE_EXCLUDE_LIST);
  136. /* and also in subdirs */
  137. assert_int_equal(check_file_full("projects/.apdisk/totally_amazing.jar"), CSYNC_FILE_EXCLUDE_LIST);
  138. /* csync-journal is ignored in general silently. */
  139. assert_int_equal(check_file_full(".csync_journal.db"), CSYNC_FILE_SILENTLY_EXCLUDED);
  140. assert_int_equal(check_file_full(".csync_journal.db.ctmp"), CSYNC_FILE_SILENTLY_EXCLUDED);
  141. assert_int_equal(check_file_full("subdir/.csync_journal.db"), CSYNC_FILE_SILENTLY_EXCLUDED);
  142. /* also the new form of the database name */
  143. assert_int_equal(check_file_full("._sync_5bdd60bdfcfa.db"), CSYNC_FILE_SILENTLY_EXCLUDED);
  144. assert_int_equal(check_file_full("._sync_5bdd60bdfcfa.db.ctmp"), CSYNC_FILE_SILENTLY_EXCLUDED);
  145. assert_int_equal(check_file_full("._sync_5bdd60bdfcfa.db-shm"), CSYNC_FILE_SILENTLY_EXCLUDED);
  146. assert_int_equal(check_file_full("subdir/._sync_5bdd60bdfcfa.db"), CSYNC_FILE_SILENTLY_EXCLUDED);
  147. assert_int_equal(check_file_full(".sync_5bdd60bdfcfa.db"), CSYNC_FILE_SILENTLY_EXCLUDED);
  148. assert_int_equal(check_file_full(".sync_5bdd60bdfcfa.db.ctmp"), CSYNC_FILE_SILENTLY_EXCLUDED);
  149. assert_int_equal(check_file_full(".sync_5bdd60bdfcfa.db-shm"), CSYNC_FILE_SILENTLY_EXCLUDED);
  150. assert_int_equal(check_file_full("subdir/.sync_5bdd60bdfcfa.db"), CSYNC_FILE_SILENTLY_EXCLUDED);
  151. /* pattern ]*.directory - ignore and remove */
  152. assert_int_equal(check_file_full("my.~directory"), CSYNC_FILE_EXCLUDE_AND_REMOVE);
  153. assert_int_equal(check_file_full("/a_folder/my.~directory"), CSYNC_FILE_EXCLUDE_AND_REMOVE);
  154. /* Not excluded because the pattern .netscape/cache requires directory. */
  155. assert_int_equal(check_file_full(".netscape/cache"), CSYNC_NOT_EXCLUDED);
  156. /* Not excluded */
  157. assert_int_equal(check_file_full("unicode/中文.hé"), CSYNC_NOT_EXCLUDED);
  158. /* excluded */
  159. assert_int_equal(check_file_full("unicode/пятницы.txt"), CSYNC_FILE_EXCLUDE_LIST);
  160. assert_int_equal(check_file_full("unicode/中文.💩"), CSYNC_FILE_EXCLUDE_LIST);
  161. /* path wildcards */
  162. assert_int_equal(check_file_full("foobar/my_manuscript.out"), CSYNC_FILE_EXCLUDE_LIST);
  163. assert_int_equal(check_file_full("latex_tmp/my_manuscript.run.xml"), CSYNC_FILE_EXCLUDE_LIST);
  164. assert_int_equal(check_file_full("word_tmp/my_manuscript.run.xml"), CSYNC_NOT_EXCLUDED);
  165. assert_int_equal(check_file_full("latex/my_manuscript.tex.tmp"), CSYNC_NOT_EXCLUDED);
  166. assert_int_equal(check_file_full("latex/songbook/my_manuscript.tex.tmp"), CSYNC_FILE_EXCLUDE_LIST);
  167. #ifdef _WIN32
  168. assert_int_equal(exclude_check_file("file_trailing_space "), CSYNC_FILE_EXCLUDE_TRAILING_SPACE);
  169. assert_int_equal(exclude_check_file("file_trailing_dot."), CSYNC_FILE_EXCLUDE_INVALID_CHAR);
  170. assert_int_equal(exclude_check_file("AUX"), CSYNC_FILE_EXCLUDE_INVALID_CHAR);
  171. assert_int_equal(exclude_check_file("file_invalid_char<"), CSYNC_FILE_EXCLUDE_INVALID_CHAR);
  172. #endif
  173. /* ? character */
  174. excludedFiles->addManualExclude("bond00?");
  175. excludedFiles->reloadExcludeFiles();
  176. assert_int_equal(check_file_full("bond00"), CSYNC_NOT_EXCLUDED);
  177. assert_int_equal(check_file_full("bond007"), CSYNC_FILE_EXCLUDE_LIST);
  178. assert_int_equal(check_file_full("bond0071"), CSYNC_NOT_EXCLUDED);
  179. /* brackets */
  180. excludedFiles->addManualExclude("a [bc] d");
  181. excludedFiles->reloadExcludeFiles();
  182. assert_int_equal(check_file_full("a d d"), CSYNC_NOT_EXCLUDED);
  183. assert_int_equal(check_file_full("a d"), CSYNC_NOT_EXCLUDED);
  184. assert_int_equal(check_file_full("a b d"), CSYNC_FILE_EXCLUDE_LIST);
  185. assert_int_equal(check_file_full("a c d"), CSYNC_FILE_EXCLUDE_LIST);
  186. /* escapes */
  187. excludedFiles->addManualExclude("a \\*");
  188. excludedFiles->addManualExclude("b \\?");
  189. excludedFiles->addManualExclude("c \\[d]");
  190. excludedFiles->reloadExcludeFiles();
  191. assert_int_equal(check_file_full("a \\*"), CSYNC_NOT_EXCLUDED);
  192. assert_int_equal(check_file_full("a bc"), CSYNC_NOT_EXCLUDED);
  193. assert_int_equal(check_file_full("a *"), CSYNC_FILE_EXCLUDE_LIST);
  194. assert_int_equal(check_file_full("b \\?"), CSYNC_NOT_EXCLUDED);
  195. assert_int_equal(check_file_full("b f"), CSYNC_NOT_EXCLUDED);
  196. assert_int_equal(check_file_full("b ?"), CSYNC_FILE_EXCLUDE_LIST);
  197. assert_int_equal(check_file_full("c \\[d]"), CSYNC_NOT_EXCLUDED);
  198. assert_int_equal(check_file_full("c d"), CSYNC_NOT_EXCLUDED);
  199. assert_int_equal(check_file_full("c [d]"), CSYNC_FILE_EXCLUDE_LIST);
  200. }
  201. static void check_csync_excluded_per_dir(void **)
  202. {
  203. excludedFiles->addManualExclude("A");
  204. excludedFiles->reloadExcludeFiles();
  205. assert_int_equal(check_file_full("A"), CSYNC_FILE_EXCLUDE_LIST);
  206. excludedFiles->clearManualExcludes();
  207. excludedFiles->addManualExclude("A", "/B/");
  208. excludedFiles->reloadExcludeFiles();
  209. assert_int_equal(check_file_full("A"), CSYNC_NOT_EXCLUDED);
  210. assert_int_equal(check_file_full("B/A"), CSYNC_FILE_EXCLUDE_LIST);
  211. excludedFiles->clearManualExcludes();
  212. excludedFiles->addManualExclude("A/a1", "/B/");
  213. excludedFiles->reloadExcludeFiles();
  214. assert_int_equal(check_file_full("A"), CSYNC_NOT_EXCLUDED);
  215. assert_int_equal(check_file_full("B/A/a1"), CSYNC_FILE_EXCLUDE_LIST);
  216. #define FOO_DIR "/tmp/check_csync1/foo"
  217. #define FOO_EXCLUDE_LIST FOO_DIR "/.sync-exclude.lst"
  218. int rc = 0;
  219. rc = system("mkdir -p " FOO_DIR);
  220. assert_int_equal(rc, 0);
  221. FILE *fh = fopen(FOO_EXCLUDE_LIST, "w");
  222. assert_non_null(fh);
  223. rc = fprintf(fh, "bar");
  224. assert_int_not_equal(rc, 0);
  225. rc = fclose(fh);
  226. assert_int_equal(rc, 0);
  227. excludedFiles->addInTreeExcludeFilePath(FOO_EXCLUDE_LIST);
  228. excludedFiles->reloadExcludeFiles();
  229. assert_int_equal(check_file_full(FOO_DIR), CSYNC_NOT_EXCLUDED);
  230. assert_int_equal(check_file_full(FOO_DIR "/bar"), CSYNC_FILE_EXCLUDE_LIST);
  231. assert_int_equal(check_file_full(FOO_DIR "/baz"), CSYNC_NOT_EXCLUDED);
  232. #undef FOO_DIR
  233. #undef FOO_EXCLUDE_LIST
  234. }
  235. static void check_csync_excluded_traversal_per_dir(void **)
  236. {
  237. assert_int_equal(check_file_traversal("/"), CSYNC_NOT_EXCLUDED);
  238. /* path wildcards */
  239. excludedFiles->addManualExclude("*/*.tex.tmp", "/latex/");
  240. assert_int_equal(check_file_traversal("latex/my_manuscript.tex.tmp"), CSYNC_NOT_EXCLUDED);
  241. assert_int_equal(check_file_traversal("latex/songbook/my_manuscript.tex.tmp"), CSYNC_FILE_EXCLUDE_LIST);
  242. }
  243. static void check_csync_excluded_traversal(void **)
  244. {
  245. assert_int_equal(check_file_traversal(""), CSYNC_NOT_EXCLUDED);
  246. assert_int_equal(check_file_traversal("/"), CSYNC_NOT_EXCLUDED);
  247. assert_int_equal(check_file_traversal("A"), CSYNC_NOT_EXCLUDED);
  248. assert_int_equal(check_file_traversal("krawel_krawel"), CSYNC_NOT_EXCLUDED);
  249. assert_int_equal(check_file_traversal(".kde/share/config/kwin.eventsrc"), CSYNC_NOT_EXCLUDED);
  250. assert_int_equal(check_dir_traversal("mozilla/.directory"), CSYNC_FILE_EXCLUDE_LIST);
  251. /*
  252. * Test for patterns in subdirs. '.beagle' is defined as a pattern and has
  253. * to be found in top dir as well as in directories underneath.
  254. */
  255. assert_int_equal(check_dir_traversal(".apdisk"), CSYNC_FILE_EXCLUDE_LIST);
  256. assert_int_equal(check_dir_traversal("foo/.apdisk"), CSYNC_FILE_EXCLUDE_LIST);
  257. assert_int_equal(check_dir_traversal("foo/bar/.apdisk"), CSYNC_FILE_EXCLUDE_LIST);
  258. assert_int_equal(check_file_traversal(".java"), CSYNC_NOT_EXCLUDED);
  259. /* csync-journal is ignored in general silently. */
  260. assert_int_equal(check_file_traversal(".csync_journal.db"), CSYNC_FILE_SILENTLY_EXCLUDED);
  261. assert_int_equal(check_file_traversal(".csync_journal.db.ctmp"), CSYNC_FILE_SILENTLY_EXCLUDED);
  262. assert_int_equal(check_file_traversal("subdir/.csync_journal.db"), CSYNC_FILE_SILENTLY_EXCLUDED);
  263. assert_int_equal(check_file_traversal("/two/subdir/.csync_journal.db"), CSYNC_FILE_SILENTLY_EXCLUDED);
  264. /* also the new form of the database name */
  265. assert_int_equal(check_file_traversal("._sync_5bdd60bdfcfa.db"), CSYNC_FILE_SILENTLY_EXCLUDED);
  266. assert_int_equal(check_file_traversal("._sync_5bdd60bdfcfa.db.ctmp"), CSYNC_FILE_SILENTLY_EXCLUDED);
  267. assert_int_equal(check_file_traversal("._sync_5bdd60bdfcfa.db-shm"), CSYNC_FILE_SILENTLY_EXCLUDED);
  268. assert_int_equal(check_file_traversal("subdir/._sync_5bdd60bdfcfa.db"), CSYNC_FILE_SILENTLY_EXCLUDED);
  269. assert_int_equal(check_file_traversal(".sync_5bdd60bdfcfa.db"), CSYNC_FILE_SILENTLY_EXCLUDED);
  270. assert_int_equal(check_file_traversal(".sync_5bdd60bdfcfa.db.ctmp"), CSYNC_FILE_SILENTLY_EXCLUDED);
  271. assert_int_equal(check_file_traversal(".sync_5bdd60bdfcfa.db-shm"), CSYNC_FILE_SILENTLY_EXCLUDED);
  272. assert_int_equal(check_file_traversal("subdir/.sync_5bdd60bdfcfa.db"), CSYNC_FILE_SILENTLY_EXCLUDED);
  273. /* Other builtin excludes */
  274. assert_int_equal(check_file_traversal("foo/Desktop.ini"), CSYNC_NOT_EXCLUDED);
  275. assert_int_equal(check_file_traversal("Desktop.ini"), CSYNC_FILE_SILENTLY_EXCLUDED);
  276. /* pattern ]*.directory - ignore and remove */
  277. assert_int_equal(check_file_traversal("my.~directory"), CSYNC_FILE_EXCLUDE_AND_REMOVE);
  278. assert_int_equal(check_file_traversal("/a_folder/my.~directory"), CSYNC_FILE_EXCLUDE_AND_REMOVE);
  279. /* Not excluded because the pattern .netscape/cache requires directory. */
  280. assert_int_equal(check_file_traversal(".netscape/cache"), CSYNC_NOT_EXCLUDED);
  281. /* Not excluded */
  282. assert_int_equal(check_file_traversal("unicode/中文.hé"), CSYNC_NOT_EXCLUDED);
  283. /* excluded */
  284. assert_int_equal(check_file_traversal("unicode/пятницы.txt"), CSYNC_FILE_EXCLUDE_LIST);
  285. assert_int_equal(check_file_traversal("unicode/中文.💩"), CSYNC_FILE_EXCLUDE_LIST);
  286. /* path wildcards */
  287. assert_int_equal(check_file_traversal("foobar/my_manuscript.out"), CSYNC_FILE_EXCLUDE_LIST);
  288. assert_int_equal(check_file_traversal("latex_tmp/my_manuscript.run.xml"), CSYNC_FILE_EXCLUDE_LIST);
  289. assert_int_equal(check_file_traversal("word_tmp/my_manuscript.run.xml"), CSYNC_NOT_EXCLUDED);
  290. assert_int_equal(check_file_traversal("latex/my_manuscript.tex.tmp"), CSYNC_NOT_EXCLUDED);
  291. assert_int_equal(check_file_traversal("latex/songbook/my_manuscript.tex.tmp"), CSYNC_FILE_EXCLUDE_LIST);
  292. #ifdef _WIN32
  293. assert_int_equal(check_file_traversal("file_trailing_space "), CSYNC_FILE_EXCLUDE_TRAILING_SPACE);
  294. assert_int_equal(check_file_traversal("file_trailing_dot."), CSYNC_FILE_EXCLUDE_INVALID_CHAR);
  295. assert_int_equal(check_file_traversal("AUX"), CSYNC_FILE_EXCLUDE_INVALID_CHAR);
  296. assert_int_equal(check_file_traversal("file_invalid_char<"), CSYNC_FILE_EXCLUDE_INVALID_CHAR);
  297. #endif
  298. /* From here the actual traversal tests */
  299. excludedFiles->addManualExclude("/exclude");
  300. excludedFiles->reloadExcludeFiles();
  301. /* Check toplevel dir, the pattern only works for toplevel dir. */
  302. assert_int_equal(check_dir_traversal("/exclude"), CSYNC_FILE_EXCLUDE_LIST);
  303. assert_int_equal(check_dir_traversal("/foo/exclude"), CSYNC_NOT_EXCLUDED);
  304. /* check for a file called exclude. Must still work */
  305. assert_int_equal(check_file_traversal("/exclude"), CSYNC_FILE_EXCLUDE_LIST);
  306. assert_int_equal(check_file_traversal("/foo/exclude"), CSYNC_NOT_EXCLUDED);
  307. /* Add an exclude for directories only: excl/ */
  308. excludedFiles->addManualExclude("excl/");
  309. excludedFiles->reloadExcludeFiles();
  310. assert_int_equal(check_dir_traversal("/excl"), CSYNC_FILE_EXCLUDE_LIST);
  311. assert_int_equal(check_dir_traversal("meep/excl"), CSYNC_FILE_EXCLUDE_LIST);
  312. // because leading dirs aren't checked!
  313. assert_int_equal(check_file_traversal("meep/excl/file"), CSYNC_NOT_EXCLUDED);
  314. assert_int_equal(check_file_traversal("/excl"), CSYNC_NOT_EXCLUDED);
  315. excludedFiles->addManualExclude("/excludepath/withsubdir");
  316. excludedFiles->reloadExcludeFiles();
  317. assert_int_equal(check_dir_traversal("/excludepath/withsubdir"), CSYNC_FILE_EXCLUDE_LIST);
  318. assert_int_equal(check_file_traversal("/excludepath/withsubdir"), CSYNC_FILE_EXCLUDE_LIST);
  319. assert_int_equal(check_dir_traversal("/excludepath/withsubdir2"), CSYNC_NOT_EXCLUDED);
  320. // because leading dirs aren't checked!
  321. assert_int_equal(check_dir_traversal("/excludepath/withsubdir/foo"), CSYNC_NOT_EXCLUDED);
  322. /* Check ending of pattern */
  323. assert_int_equal(check_file_traversal("/exclude"), CSYNC_FILE_EXCLUDE_LIST);
  324. assert_int_equal(check_file_traversal("/excludeX"), CSYNC_NOT_EXCLUDED);
  325. assert_int_equal(check_file_traversal("exclude"), CSYNC_NOT_EXCLUDED);
  326. excludedFiles->addManualExclude("exclude");
  327. excludedFiles->reloadExcludeFiles();
  328. assert_int_equal(check_file_traversal("exclude"), CSYNC_FILE_EXCLUDE_LIST);
  329. /* ? character */
  330. excludedFiles->addManualExclude("bond00?");
  331. excludedFiles->reloadExcludeFiles();
  332. assert_int_equal(check_file_traversal("bond00"), CSYNC_NOT_EXCLUDED);
  333. assert_int_equal(check_file_traversal("bond007"), CSYNC_FILE_EXCLUDE_LIST);
  334. assert_int_equal(check_file_traversal("bond0071"), CSYNC_NOT_EXCLUDED);
  335. /* brackets */
  336. excludedFiles->addManualExclude("a [bc] d");
  337. excludedFiles->reloadExcludeFiles();
  338. assert_int_equal(check_file_traversal("a d d"), CSYNC_NOT_EXCLUDED);
  339. assert_int_equal(check_file_traversal("a d"), CSYNC_NOT_EXCLUDED);
  340. assert_int_equal(check_file_traversal("a b d"), CSYNC_FILE_EXCLUDE_LIST);
  341. assert_int_equal(check_file_traversal("a c d"), CSYNC_FILE_EXCLUDE_LIST);
  342. /* escapes */
  343. excludedFiles->addManualExclude("a \\*");
  344. excludedFiles->addManualExclude("b \\?");
  345. excludedFiles->addManualExclude("c \\[d]");
  346. excludedFiles->reloadExcludeFiles();
  347. assert_int_equal(check_file_traversal("a \\*"), CSYNC_NOT_EXCLUDED);
  348. assert_int_equal(check_file_traversal("a bc"), CSYNC_NOT_EXCLUDED);
  349. assert_int_equal(check_file_traversal("a *"), CSYNC_FILE_EXCLUDE_LIST);
  350. assert_int_equal(check_file_traversal("b \\?"), CSYNC_NOT_EXCLUDED);
  351. assert_int_equal(check_file_traversal("b f"), CSYNC_NOT_EXCLUDED);
  352. assert_int_equal(check_file_traversal("b ?"), CSYNC_FILE_EXCLUDE_LIST);
  353. assert_int_equal(check_file_traversal("c \\[d]"), CSYNC_NOT_EXCLUDED);
  354. assert_int_equal(check_file_traversal("c d"), CSYNC_NOT_EXCLUDED);
  355. assert_int_equal(check_file_traversal("c [d]"), CSYNC_FILE_EXCLUDE_LIST);
  356. }
  357. static void check_csync_dir_only(void **)
  358. {
  359. excludedFiles->addManualExclude("filedir");
  360. excludedFiles->addManualExclude("dir/");
  361. assert_int_equal(check_file_traversal("other"), CSYNC_NOT_EXCLUDED);
  362. assert_int_equal(check_file_traversal("filedir"), CSYNC_FILE_EXCLUDE_LIST);
  363. assert_int_equal(check_file_traversal("dir"), CSYNC_NOT_EXCLUDED);
  364. assert_int_equal(check_file_traversal("s/other"), CSYNC_NOT_EXCLUDED);
  365. assert_int_equal(check_file_traversal("s/filedir"), CSYNC_FILE_EXCLUDE_LIST);
  366. assert_int_equal(check_file_traversal("s/dir"), CSYNC_NOT_EXCLUDED);
  367. assert_int_equal(check_dir_traversal("other"), CSYNC_NOT_EXCLUDED);
  368. assert_int_equal(check_dir_traversal("filedir"), CSYNC_FILE_EXCLUDE_LIST);
  369. assert_int_equal(check_dir_traversal("dir"), CSYNC_FILE_EXCLUDE_LIST);
  370. assert_int_equal(check_dir_traversal("s/other"), CSYNC_NOT_EXCLUDED);
  371. assert_int_equal(check_dir_traversal("s/filedir"), CSYNC_FILE_EXCLUDE_LIST);
  372. assert_int_equal(check_dir_traversal("s/dir"), CSYNC_FILE_EXCLUDE_LIST);
  373. assert_int_equal(check_dir_full("filedir/foo"), CSYNC_FILE_EXCLUDE_LIST);
  374. assert_int_equal(check_file_full("filedir/foo"), CSYNC_FILE_EXCLUDE_LIST);
  375. assert_int_equal(check_dir_full("dir/foo"), CSYNC_FILE_EXCLUDE_LIST);
  376. assert_int_equal(check_file_full("dir/foo"), CSYNC_FILE_EXCLUDE_LIST);
  377. }
  378. static void check_csync_pathes(void **)
  379. {
  380. excludedFiles->addManualExclude("/exclude");
  381. excludedFiles->reloadExcludeFiles();
  382. /* Check toplevel dir, the pattern only works for toplevel dir. */
  383. assert_int_equal(check_dir_full("/exclude"), CSYNC_FILE_EXCLUDE_LIST);
  384. assert_int_equal(check_dir_full("/foo/exclude"), CSYNC_NOT_EXCLUDED);
  385. /* check for a file called exclude. Must still work */
  386. assert_int_equal(check_file_full("/exclude"), CSYNC_FILE_EXCLUDE_LIST);
  387. assert_int_equal(check_file_full("/foo/exclude"), CSYNC_NOT_EXCLUDED);
  388. /* Add an exclude for directories only: excl/ */
  389. excludedFiles->addManualExclude("excl/");
  390. excludedFiles->reloadExcludeFiles();
  391. assert_int_equal(check_dir_full("/excl"), CSYNC_FILE_EXCLUDE_LIST);
  392. assert_int_equal(check_dir_full("meep/excl"), CSYNC_FILE_EXCLUDE_LIST);
  393. assert_int_equal(check_file_full("meep/excl/file"), CSYNC_FILE_EXCLUDE_LIST);
  394. assert_int_equal(check_file_full("/excl"), CSYNC_NOT_EXCLUDED);
  395. excludedFiles->addManualExclude("/excludepath/withsubdir");
  396. excludedFiles->reloadExcludeFiles();
  397. assert_int_equal(check_dir_full("/excludepath/withsubdir"), CSYNC_FILE_EXCLUDE_LIST);
  398. assert_int_equal(check_file_full("/excludepath/withsubdir"), CSYNC_FILE_EXCLUDE_LIST);
  399. assert_int_equal(check_dir_full("/excludepath/withsubdir2"), CSYNC_NOT_EXCLUDED);
  400. assert_int_equal(check_dir_full("/excludepath/withsubdir/foo"), CSYNC_FILE_EXCLUDE_LIST);
  401. }
  402. static void check_csync_wildcards(void **)
  403. {
  404. excludedFiles->addManualExclude("a/foo*bar");
  405. excludedFiles->addManualExclude("b/foo*bar*");
  406. excludedFiles->addManualExclude("c/foo?bar");
  407. excludedFiles->addManualExclude("d/foo?bar*");
  408. excludedFiles->addManualExclude("e/foo?bar?");
  409. excludedFiles->addManualExclude("g/bar*");
  410. excludedFiles->addManualExclude("h/bar?");
  411. excludedFiles->setWildcardsMatchSlash(false);
  412. assert_int_equal(check_file_traversal("a/fooXYZbar"), CSYNC_FILE_EXCLUDE_LIST);
  413. assert_int_equal(check_file_traversal("a/fooX/Zbar"), CSYNC_NOT_EXCLUDED);
  414. assert_int_equal(check_file_traversal("b/fooXYZbarABC"), CSYNC_FILE_EXCLUDE_LIST);
  415. assert_int_equal(check_file_traversal("b/fooX/ZbarABC"), CSYNC_NOT_EXCLUDED);
  416. assert_int_equal(check_file_traversal("c/fooXbar"), CSYNC_FILE_EXCLUDE_LIST);
  417. assert_int_equal(check_file_traversal("c/foo/bar"), CSYNC_NOT_EXCLUDED);
  418. assert_int_equal(check_file_traversal("d/fooXbarABC"), CSYNC_FILE_EXCLUDE_LIST);
  419. assert_int_equal(check_file_traversal("d/foo/barABC"), CSYNC_NOT_EXCLUDED);
  420. assert_int_equal(check_file_traversal("e/fooXbarA"), CSYNC_FILE_EXCLUDE_LIST);
  421. assert_int_equal(check_file_traversal("e/foo/barA"), CSYNC_NOT_EXCLUDED);
  422. assert_int_equal(check_file_traversal("g/barABC"), CSYNC_FILE_EXCLUDE_LIST);
  423. assert_int_equal(check_file_traversal("g/XbarABC"), CSYNC_NOT_EXCLUDED);
  424. assert_int_equal(check_file_traversal("h/barZ"), CSYNC_FILE_EXCLUDE_LIST);
  425. assert_int_equal(check_file_traversal("h/XbarZ"), CSYNC_NOT_EXCLUDED);
  426. excludedFiles->setWildcardsMatchSlash(true);
  427. assert_int_equal(check_file_traversal("a/fooX/Zbar"), CSYNC_FILE_EXCLUDE_LIST);
  428. assert_int_equal(check_file_traversal("b/fooX/ZbarABC"), CSYNC_FILE_EXCLUDE_LIST);
  429. assert_int_equal(check_file_traversal("c/foo/bar"), CSYNC_FILE_EXCLUDE_LIST);
  430. assert_int_equal(check_file_traversal("d/foo/barABC"), CSYNC_FILE_EXCLUDE_LIST);
  431. assert_int_equal(check_file_traversal("e/foo/barA"), CSYNC_FILE_EXCLUDE_LIST);
  432. }
  433. static void check_csync_regex_translation(void **)
  434. {
  435. QByteArray storage;
  436. auto translate = [&storage](const char *pattern) {
  437. storage = convertToRegexpSyntax(pattern, false).toUtf8();
  438. return storage.constData();
  439. };
  440. assert_string_equal(translate(""), "");
  441. assert_string_equal(translate("abc"), "abc");
  442. assert_string_equal(translate("a*c"), "a[^/]*c");
  443. assert_string_equal(translate("a?c"), "a[^/]c");
  444. assert_string_equal(translate("a[xyz]c"), "a[xyz]c");
  445. assert_string_equal(translate("a[xyzc"), "a\\[xyzc");
  446. assert_string_equal(translate("a[!xyz]c"), "a[^xyz]c");
  447. assert_string_equal(translate("a\\*b\\?c\\[d\\\\e"), "a\\*b\\?c\\[d\\\\e");
  448. assert_string_equal(translate("a.c"), "a\\.c");
  449. assert_string_equal(translate("?𠜎?"), "[^/]\\𠜎[^/]"); // 𠜎 is 4-byte utf8
  450. }
  451. static void check_csync_bname_trigger(void **)
  452. {
  453. bool wildcardsMatchSlash = false;
  454. QByteArray storage;
  455. auto translate = [&storage, &wildcardsMatchSlash](const char *pattern) {
  456. storage = extractBnameTrigger(pattern, wildcardsMatchSlash).toUtf8();
  457. return storage.constData();
  458. };
  459. assert_string_equal(translate(""), "");
  460. assert_string_equal(translate("a/b/"), "");
  461. assert_string_equal(translate("a/b/c"), "c");
  462. assert_string_equal(translate("c"), "c");
  463. assert_string_equal(translate("a/foo*"), "foo*");
  464. assert_string_equal(translate("a/abc*foo*"), "abc*foo*");
  465. wildcardsMatchSlash = true;
  466. assert_string_equal(translate(""), "");
  467. assert_string_equal(translate("a/b/"), "");
  468. assert_string_equal(translate("a/b/c"), "c");
  469. assert_string_equal(translate("c"), "c");
  470. assert_string_equal(translate("*"), "*");
  471. assert_string_equal(translate("a/foo*"), "foo*");
  472. assert_string_equal(translate("a/abc?foo*"), "*foo*");
  473. assert_string_equal(translate("a/abc*foo*"), "*foo*");
  474. assert_string_equal(translate("a/abc?foo?"), "*foo?");
  475. assert_string_equal(translate("a/abc*foo?*"), "*foo?*");
  476. assert_string_equal(translate("a/abc*/foo*"), "foo*");
  477. }
  478. static void check_csync_is_windows_reserved_word(void **)
  479. {
  480. assert_true(csync_is_windows_reserved_word("CON"));
  481. assert_true(csync_is_windows_reserved_word("con"));
  482. assert_true(csync_is_windows_reserved_word("CON."));
  483. assert_true(csync_is_windows_reserved_word("con."));
  484. assert_true(csync_is_windows_reserved_word("CON.ference"));
  485. assert_false(csync_is_windows_reserved_word("CONference"));
  486. assert_false(csync_is_windows_reserved_word("conference"));
  487. assert_false(csync_is_windows_reserved_word("conf.erence"));
  488. assert_false(csync_is_windows_reserved_word("co"));
  489. assert_true(csync_is_windows_reserved_word("COM2"));
  490. assert_true(csync_is_windows_reserved_word("com2"));
  491. assert_true(csync_is_windows_reserved_word("COM2."));
  492. assert_true(csync_is_windows_reserved_word("com2."));
  493. assert_true(csync_is_windows_reserved_word("COM2.ference"));
  494. assert_false(csync_is_windows_reserved_word("COM2ference"));
  495. assert_false(csync_is_windows_reserved_word("com2ference"));
  496. assert_false(csync_is_windows_reserved_word("com2f.erence"));
  497. assert_false(csync_is_windows_reserved_word("com"));
  498. assert_true(csync_is_windows_reserved_word("CLOCK$"));
  499. assert_true(csync_is_windows_reserved_word("$Recycle.Bin"));
  500. assert_true(csync_is_windows_reserved_word("ClocK$"));
  501. assert_true(csync_is_windows_reserved_word("$recycle.bin"));
  502. assert_true(csync_is_windows_reserved_word("A:"));
  503. assert_true(csync_is_windows_reserved_word("a:"));
  504. assert_true(csync_is_windows_reserved_word("z:"));
  505. assert_true(csync_is_windows_reserved_word("Z:"));
  506. assert_true(csync_is_windows_reserved_word("M:"));
  507. assert_true(csync_is_windows_reserved_word("m:"));
  508. }
  509. /* QT_ENABLE_REGEXP_JIT=0 to get slower results :-) */
  510. static void check_csync_excluded_performance(void **)
  511. {
  512. const int N = 10000;
  513. int totalRc = 0;
  514. int i = 0;
  515. // Being able to use QElapsedTimer for measurement would be nice...
  516. {
  517. struct timeval before, after;
  518. gettimeofday(&before, 0);
  519. for (i = 0; i < N; ++i) {
  520. totalRc += check_dir_full("/this/is/quite/a/long/path/with/many/components");
  521. totalRc += check_file_full("/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");
  522. }
  523. assert_int_equal(totalRc, CSYNC_NOT_EXCLUDED); // mainly to avoid optimization
  524. gettimeofday(&after, 0);
  525. const double total = (after.tv_sec - before.tv_sec)
  526. + (after.tv_usec - before.tv_usec) / 1.0e6;
  527. const double perCallMs = total / 2 / N * 1000;
  528. printf("csync_excluded: %f ms per call\n", perCallMs);
  529. }
  530. {
  531. struct timeval before, after;
  532. gettimeofday(&before, 0);
  533. for (i = 0; i < N; ++i) {
  534. totalRc += check_dir_traversal("/this/is/quite/a/long/path/with/many/components");
  535. totalRc += check_file_traversal("/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");
  536. }
  537. assert_int_equal(totalRc, CSYNC_NOT_EXCLUDED); // mainly to avoid optimization
  538. gettimeofday(&after, 0);
  539. const double total = (after.tv_sec - before.tv_sec)
  540. + (after.tv_usec - before.tv_usec) / 1.0e6;
  541. const double perCallMs = total / 2 / N * 1000;
  542. printf("csync_excluded_traversal: %f ms per call\n", perCallMs);
  543. }
  544. }
  545. static void check_csync_exclude_expand_escapes(void **state)
  546. {
  547. (void)state;
  548. QByteArray line = R"(keep \' \" \? \\ \a \b \f \n \r \t \v \z \#)";
  549. csync_exclude_expand_escapes(line);
  550. assert_true(0 == strcmp(line.constData(), "keep ' \" ? \\\\ \a \b \f \n \r \t \v \\z #"));
  551. line = "";
  552. csync_exclude_expand_escapes(line);
  553. assert_true(0 == strcmp(line.constData(), ""));
  554. line = "\\";
  555. csync_exclude_expand_escapes(line);
  556. assert_true(0 == strcmp(line.constData(), "\\"));
  557. }
  558. }; // class ExcludedFilesTest
  559. int torture_run_tests(void)
  560. {
  561. using T = ExcludedFilesTest;
  562. const struct CMUnitTest tests[] = {
  563. cmocka_unit_test_setup_teardown(T::check_csync_exclude_add, T::setup, T::teardown),
  564. cmocka_unit_test_setup_teardown(T::check_csync_exclude_add_per_dir, T::setup, T::teardown),
  565. cmocka_unit_test_setup_teardown(T::check_csync_excluded, T::setup_init, T::teardown),
  566. cmocka_unit_test_setup_teardown(T::check_csync_excluded_per_dir, T::setup, T::teardown),
  567. cmocka_unit_test_setup_teardown(T::check_csync_excluded_traversal, T::setup_init, T::teardown),
  568. cmocka_unit_test_setup_teardown(T::check_csync_excluded_traversal_per_dir, T::setup, T::teardown),
  569. cmocka_unit_test_setup_teardown(T::check_csync_dir_only, T::setup, T::teardown),
  570. cmocka_unit_test_setup_teardown(T::check_csync_pathes, T::setup_init, T::teardown),
  571. cmocka_unit_test_setup_teardown(T::check_csync_wildcards, T::setup, T::teardown),
  572. cmocka_unit_test_setup_teardown(T::check_csync_regex_translation, T::setup, T::teardown),
  573. cmocka_unit_test_setup_teardown(T::check_csync_bname_trigger, T::setup, T::teardown),
  574. cmocka_unit_test_setup_teardown(T::check_csync_is_windows_reserved_word, T::setup_init, T::teardown),
  575. cmocka_unit_test_setup_teardown(T::check_csync_excluded_performance, T::setup_init, T::teardown),
  576. cmocka_unit_test(T::check_csync_exclude_expand_escapes),
  577. };
  578. return cmocka_run_group_tests(tests, nullptr, nullptr);
  579. }