053-scan_task.cpp 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814
  1. // SPDX-License-Identifier: GPL-3.0-or-later
  2. // SPDX-FileCopyrightText: 2019-2024 Ivan Baidakou
  3. #include "test-utils.h"
  4. #include "fs/scan_task.h"
  5. #include "model/misc/sequencer.h"
  6. using namespace syncspirit;
  7. using namespace syncspirit::test;
  8. using namespace syncspirit::utils;
  9. using namespace syncspirit::model;
  10. using namespace syncspirit::fs;
  11. TEST_CASE("scan_task", "[fs]") {
  12. utils::set_default("trace");
  13. auto root_path = bfs::unique_path();
  14. bfs::create_directories(root_path);
  15. path_guard_t path_quard{root_path};
  16. config::fs_config_t config{3600, 10, 1024 * 1024, 100};
  17. auto my_id = device_id_t::from_string("KHQNO2S-5QSILRK-YX4JZZ4-7L77APM-QNVGZJT-EKU7IFI-PNEPBMY-4MXFMQD").value();
  18. auto my_device = device_t::create(my_id, "my-device").value();
  19. auto peer_id = device_id_t::from_string("VUV42CZ-IQD5A37-RPEBPM4-VVQK6E4-6WSKC7B-PVJQHHD-4PZD44V-ENC6WAZ").value();
  20. auto peer_device = device_t::create(peer_id, "peer-device").value();
  21. auto peer2_id = device_id_t::from_string("XBOWTOU-Y7H6RM6-D7WT3UB-7P2DZ5G-R6GNZG6-T5CCG54-SGVF3U5-LBM7RQB").value();
  22. auto peer2_device = device_t::create(peer2_id, "peer2-device").value();
  23. auto cluster = cluster_ptr_t(new cluster_t(my_device, 1));
  24. auto sequencer = make_sequencer(4);
  25. cluster->get_devices().put(my_device);
  26. cluster->get_devices().put(peer_device);
  27. cluster->get_devices().put(peer2_device);
  28. auto db_folder = db::Folder();
  29. db_folder.set_id("some-id");
  30. db_folder.set_label("zzz");
  31. db_folder.set_path(root_path.string());
  32. auto folder = folder_t::create(sequencer->next_uuid(), db_folder).value();
  33. cluster->get_folders().put(folder);
  34. db::FolderInfo db_folder_info;
  35. db_folder_info.set_index_id(1234);
  36. db_folder_info.set_max_sequence(3);
  37. auto folder_my = folder_info_t::create(sequencer->next_uuid(), db_folder_info, my_device, folder).value();
  38. auto folder_peer = folder_info_t::create(sequencer->next_uuid(), db_folder_info, peer_device, folder).value();
  39. auto folder_peer2 = folder_info_t::create(sequencer->next_uuid(), db_folder_info, peer2_device, folder).value();
  40. folder->get_folder_infos().put(folder_my);
  41. folder->get_folder_infos().put(folder_peer);
  42. folder->get_folder_infos().put(folder_peer2);
  43. SECTION("without files") {
  44. #ifndef SYNCSPIRIT_WIN
  45. SECTION("no permissions to read dir => err") {
  46. bfs::permissions(root_path, bfs::perms::no_perms);
  47. auto folder_info = folder_info_t::create(sequencer->next_uuid(), db_folder_info, my_device, folder).value();
  48. folder->get_folder_infos().put(folder_info);
  49. auto task = scan_task_t(cluster, folder->get_id(), config);
  50. auto r = task.advance();
  51. CHECK(std::get_if<scan_errors_t>(&r));
  52. auto errs = std::get_if<scan_errors_t>(&r);
  53. REQUIRE(errs->size() == 1);
  54. auto &err = errs->at(0);
  55. CHECK(err.ec);
  56. CHECK(err.path == root_path);
  57. }
  58. #endif
  59. SECTION("no dirs, no files") {
  60. auto task = scan_task_t(cluster, folder->get_id(), config);
  61. auto r = task.advance();
  62. CHECK(std::get_if<bool>(&r));
  63. CHECK(*std::get_if<bool>(&r) == true);
  64. r = task.advance();
  65. CHECK(std::get_if<bool>(&r));
  66. CHECK(*std::get_if<bool>(&r) == false);
  67. }
  68. SECTION("some dirs, no files") {
  69. auto task = scan_task_t(cluster, folder->get_id(), config);
  70. auto dir = root_path / "some-dir";
  71. bfs::create_directories(dir);
  72. auto r = task.advance();
  73. CHECK(std::get_if<bool>(&r));
  74. CHECK(*std::get_if<bool>(&r) == true);
  75. r = task.advance();
  76. auto *uf = std::get_if<unknown_file_t>(&r);
  77. REQUIRE(uf);
  78. CHECK(uf->path.filename() == "some-dir");
  79. CHECK(uf->metadata.size() == 0);
  80. CHECK(uf->metadata.type() == proto::FileInfoType::DIRECTORY);
  81. r = task.advance();
  82. CHECK(std::get_if<bool>(&r));
  83. CHECK(*std::get_if<bool>(&r) == true);
  84. r = task.advance();
  85. CHECK(std::get_if<bool>(&r));
  86. CHECK(*std::get_if<bool>(&r) == false);
  87. }
  88. SECTION("no dirs, unknown files") {
  89. auto task = scan_task_t(cluster, folder->get_id(), config);
  90. write_file(root_path / "some-file", "");
  91. auto r = task.advance();
  92. CHECK(std::get_if<bool>(&r));
  93. CHECK(*std::get_if<bool>(&r) == true);
  94. r = task.advance();
  95. auto *uf = std::get_if<unknown_file_t>(&r);
  96. REQUIRE(uf);
  97. CHECK(uf->path.filename() == "some-file");
  98. CHECK(uf->metadata.size() == 0);
  99. CHECK(uf->metadata.type() == proto::FileInfoType::FILE);
  100. r = task.advance();
  101. REQUIRE(std::get_if<bool>(&r));
  102. CHECK(*std::get_if<bool>(&r) == false);
  103. }
  104. SECTION("no dirs, symlink to non-existing target") {
  105. auto task = scan_task_t(cluster, folder->get_id(), config);
  106. auto file_path = root_path / "symlink";
  107. bfs::create_symlink(bfs::path("/some/where"), file_path);
  108. auto r = task.advance();
  109. CHECK(std::get_if<bool>(&r));
  110. CHECK(*std::get_if<bool>(&r) == true);
  111. r = task.advance();
  112. auto *uf = std::get_if<unknown_file_t>(&r);
  113. REQUIRE(uf);
  114. CHECK(uf->path.filename() == "symlink");
  115. CHECK(uf->metadata.size() == 0);
  116. CHECK(uf->metadata.type() == proto::FileInfoType::SYMLINK);
  117. CHECK(uf->metadata.symlink_target() == "/some/where");
  118. r = task.advance();
  119. REQUIRE(std::get_if<bool>(&r));
  120. CHECK(*std::get_if<bool>(&r) == false);
  121. }
  122. }
  123. SECTION("regular files") {
  124. auto modified = std::time_t{1642007468};
  125. auto pr_file = proto::FileInfo{};
  126. pr_file.set_name("a.txt");
  127. pr_file.set_sequence(4);
  128. auto version = pr_file.mutable_version();
  129. auto counter = version->add_counters();
  130. counter->set_value(1);
  131. counter->set_id(peer_device->device_id().get_uint());
  132. SECTION("meta is not changed (file)") {
  133. pr_file.set_block_size(5);
  134. pr_file.set_size(5);
  135. pr_file.set_modified_s(modified);
  136. auto path = root_path / "a.txt";
  137. write_file(path, "12345");
  138. bfs::last_write_time(path, modified);
  139. auto status = bfs::status(path);
  140. pr_file.set_permissions(static_cast<uint32_t>(status.permissions()));
  141. auto file = file_info_t::create(sequencer->next_uuid(), pr_file, folder_my).value();
  142. REQUIRE(folder_my->add_strict(file));
  143. auto task = scan_task_t(cluster, folder->get_id(), config);
  144. auto r = task.advance();
  145. CHECK(std::get_if<bool>(&r));
  146. CHECK(*std::get_if<bool>(&r) == true);
  147. r = task.advance();
  148. REQUIRE(std::get_if<unchanged_meta_t>(&r));
  149. auto ref = std::get_if<unchanged_meta_t>(&r);
  150. CHECK(ref->file == file);
  151. r = task.advance();
  152. CHECK(std::get_if<bool>(&r));
  153. CHECK(*std::get_if<bool>(&r) == false);
  154. }
  155. SECTION("meta is not changed (dir)") {
  156. pr_file.set_name("a-dir");
  157. pr_file.set_type(proto::FileInfoType::DIRECTORY);
  158. auto dir = root_path / "a-dir";
  159. bfs::create_directories(dir);
  160. auto file = file_info_t::create(sequencer->next_uuid(), pr_file, folder_my).value();
  161. REQUIRE(folder_my->add_strict(file));
  162. auto task = scan_task_t(cluster, folder->get_id(), config);
  163. auto r = task.advance();
  164. CHECK(std::get_if<bool>(&r));
  165. CHECK(*std::get_if<bool>(&r) == true);
  166. r = task.advance();
  167. REQUIRE(std::get_if<unchanged_meta_t>(&r));
  168. auto ref = std::get_if<unchanged_meta_t>(&r);
  169. CHECK(ref->file == file);
  170. r = task.advance();
  171. CHECK(std::get_if<bool>(&r));
  172. CHECK(*std::get_if<bool>(&r) == true);
  173. r = task.advance();
  174. CHECK(std::get_if<bool>(&r));
  175. CHECK(*std::get_if<bool>(&r) == false);
  176. }
  177. SECTION("meta is not changed (dir + file inside)") {
  178. auto pr_dir = pr_file;
  179. pr_dir.set_name("a-dir-2");
  180. pr_dir.set_type(proto::FileInfoType::DIRECTORY);
  181. pr_dir.set_sequence(pr_file.sequence() + 1);
  182. pr_file.set_block_size(5);
  183. pr_file.set_size(5);
  184. pr_file.set_modified_s(modified);
  185. pr_file.set_name("a-dir-2/a.txt");
  186. auto dir = root_path / "a-dir-2";
  187. bfs::create_directories(dir);
  188. auto path = root_path / "a-dir-2" / "a.txt";
  189. write_file(path, "12345");
  190. bfs::last_write_time(path, modified);
  191. auto status = bfs::status(path);
  192. pr_file.set_permissions(static_cast<uint32_t>(status.permissions()));
  193. auto info_file = file_info_t::create(sequencer->next_uuid(), pr_file, folder_my).value();
  194. REQUIRE(folder_my->add_strict(info_file));
  195. auto info_dir = file_info_t::create(sequencer->next_uuid(), pr_dir, folder_my).value();
  196. REQUIRE(folder_my->add_strict(info_dir));
  197. auto task = scan_task_t(cluster, folder->get_id(), config);
  198. auto r = task.advance();
  199. CHECK(std::get_if<bool>(&r));
  200. CHECK(*std::get_if<bool>(&r) == true);
  201. r = task.advance();
  202. REQUIRE(std::get_if<unchanged_meta_t>(&r));
  203. auto ref = std::get_if<unchanged_meta_t>(&r);
  204. CHECK(ref->file == info_dir);
  205. r = task.advance();
  206. CHECK(std::get_if<bool>(&r));
  207. CHECK(*std::get_if<bool>(&r) == true);
  208. r = task.advance();
  209. REQUIRE(std::get_if<unchanged_meta_t>(&r));
  210. ref = std::get_if<unchanged_meta_t>(&r);
  211. CHECK(ref->file == info_file);
  212. r = task.advance();
  213. CHECK(std::get_if<bool>(&r));
  214. CHECK(*std::get_if<bool>(&r) == false);
  215. }
  216. SECTION("file has been removed") {
  217. pr_file.set_block_size(5);
  218. pr_file.set_size(5);
  219. pr_file.set_modified_s(modified);
  220. auto file = file_info_t::create(sequencer->next_uuid(), pr_file, folder_my).value();
  221. REQUIRE(folder_my->add_strict(file));
  222. auto task = scan_task_t(cluster, folder->get_id(), config);
  223. auto r = task.advance();
  224. CHECK(std::get_if<bool>(&r));
  225. CHECK(*std::get_if<bool>(&r) == true);
  226. r = task.advance();
  227. REQUIRE(std::get_if<removed_t>(&r));
  228. auto ref = std::get_if<removed_t>(&r);
  229. CHECK(ref->file == file);
  230. r = task.advance();
  231. CHECK(std::get_if<bool>(&r));
  232. CHECK(*std::get_if<bool>(&r) == false);
  233. }
  234. SECTION("dir has been removed") {
  235. pr_file.set_name("a-dir");
  236. pr_file.set_type(proto::FileInfoType::DIRECTORY);
  237. auto file = file_info_t::create(sequencer->next_uuid(), pr_file, folder_my).value();
  238. REQUIRE(folder_my->add_strict(file));
  239. auto task = scan_task_t(cluster, folder->get_id(), config);
  240. auto r = task.advance();
  241. CHECK(std::get_if<bool>(&r));
  242. CHECK(*std::get_if<bool>(&r) == true);
  243. r = task.advance();
  244. REQUIRE(std::get_if<removed_t>(&r));
  245. auto ref = std::get_if<removed_t>(&r);
  246. CHECK(ref->file == file);
  247. r = task.advance();
  248. CHECK(std::get_if<bool>(&r));
  249. CHECK(*std::get_if<bool>(&r) == false);
  250. }
  251. SECTION("removed file does not exist => unchanged meta") {
  252. pr_file.set_deleted(true);
  253. auto file = file_info_t::create(sequencer->next_uuid(), pr_file, folder_my).value();
  254. REQUIRE(folder_my->add_strict(file));
  255. auto task = scan_task_t(cluster, folder->get_id(), config);
  256. auto r = task.advance();
  257. CHECK(std::get_if<bool>(&r));
  258. CHECK(*std::get_if<bool>(&r) == true);
  259. r = task.advance();
  260. REQUIRE(std::get_if<unchanged_meta_t>(&r));
  261. auto ref = std::get_if<unchanged_meta_t>(&r);
  262. CHECK(ref->file == file);
  263. r = task.advance();
  264. CHECK(std::get_if<bool>(&r));
  265. CHECK(*std::get_if<bool>(&r) == false);
  266. }
  267. SECTION("removed dir does not exist => unchanged meta") {
  268. pr_file.set_deleted(true);
  269. pr_file.set_type(proto::FileInfoType::DIRECTORY);
  270. auto file = file_info_t::create(sequencer->next_uuid(), pr_file, folder_my).value();
  271. REQUIRE(folder_my->add_strict(file));
  272. auto task = scan_task_t(cluster, folder->get_id(), config);
  273. auto r = task.advance();
  274. CHECK(std::get_if<bool>(&r));
  275. CHECK(*std::get_if<bool>(&r) == true);
  276. r = task.advance();
  277. REQUIRE(std::get_if<unchanged_meta_t>(&r));
  278. auto ref = std::get_if<unchanged_meta_t>(&r);
  279. CHECK(ref->file == file);
  280. r = task.advance();
  281. CHECK(std::get_if<bool>(&r));
  282. CHECK(*std::get_if<bool>(&r) == false);
  283. }
  284. SECTION("root dir does not exist & deleted file => unchanged meta") {
  285. pr_file.set_deleted(true);
  286. folder->set_path(root_path / "zzz");
  287. auto file = file_info_t::create(sequencer->next_uuid(), pr_file, folder_my).value();
  288. REQUIRE(folder_my->add_strict(file));
  289. auto task = scan_task_t(cluster, folder->get_id(), config);
  290. auto r = task.advance();
  291. REQUIRE(std::get_if<bool>(&r));
  292. CHECK(*std::get_if<bool>(&r) == true);
  293. r = task.advance();
  294. REQUIRE(std::get_if<unchanged_meta_t>(&r));
  295. auto ref = std::get_if<unchanged_meta_t>(&r);
  296. CHECK(ref->file == file);
  297. r = task.advance();
  298. CHECK(std::get_if<bool>(&r));
  299. CHECK(*std::get_if<bool>(&r) == false);
  300. }
  301. SECTION("meta is changed") {
  302. auto task = scan_task_ptr_t{};
  303. auto file = file_info_ptr_t{};
  304. auto r = scan_result_t{};
  305. SECTION("file size differs") {
  306. pr_file.set_block_size(5);
  307. pr_file.set_size(6);
  308. pr_file.set_modified_s(modified);
  309. auto path = root_path / "a.txt";
  310. write_file(path, "12345");
  311. bfs::last_write_time(path, modified);
  312. auto status = bfs::status(path);
  313. pr_file.set_permissions(static_cast<uint32_t>(status.permissions()));
  314. file = file_info_t::create(sequencer->next_uuid(), pr_file, folder_my).value();
  315. REQUIRE(folder_my->add_strict(file));
  316. task = new scan_task_t(cluster, folder->get_id(), config);
  317. r = task->advance();
  318. CHECK(std::get_if<bool>(&r));
  319. CHECK(*std::get_if<bool>(&r) == true);
  320. r = task->advance();
  321. REQUIRE(std::get_if<changed_meta_t>(&r));
  322. auto ref = std::get_if<changed_meta_t>(&r);
  323. CHECK(ref->file == file);
  324. CHECK(ref->metadata.size() == 5);
  325. CHECK(ref->metadata.modified_s() == modified);
  326. }
  327. SECTION("modification time differs") {
  328. pr_file.set_block_size(5);
  329. pr_file.set_size(5);
  330. pr_file.set_modified_s(modified + 1);
  331. auto path = root_path / "a.txt";
  332. write_file(path, "12345");
  333. bfs::last_write_time(path, modified);
  334. auto status = bfs::status(path);
  335. pr_file.set_permissions(static_cast<uint32_t>(status.permissions()));
  336. file = file_info_t::create(sequencer->next_uuid(), pr_file, folder_my).value();
  337. REQUIRE(folder_my->add_strict(file));
  338. task = new scan_task_t(cluster, folder->get_id(), config);
  339. r = task->advance();
  340. CHECK(std::get_if<bool>(&r));
  341. CHECK(*std::get_if<bool>(&r) == true);
  342. r = task->advance();
  343. REQUIRE(std::get_if<changed_meta_t>(&r));
  344. auto ref = std::get_if<changed_meta_t>(&r);
  345. CHECK(ref->file == file);
  346. CHECK(ref->metadata.size() == 5);
  347. CHECK(ref->metadata.modified_s() == modified);
  348. }
  349. SECTION("permissions differs") {
  350. pr_file.set_block_size(5);
  351. pr_file.set_size(5);
  352. pr_file.set_modified_s(modified);
  353. pr_file.set_permissions(static_cast<uint32_t>(-1));
  354. auto path = root_path / "a.txt";
  355. write_file(path, "12345");
  356. bfs::last_write_time(path, modified);
  357. file = file_info_t::create(sequencer->next_uuid(), pr_file, folder_my).value();
  358. REQUIRE(folder_my->add_strict(file));
  359. task = new scan_task_t(cluster, folder->get_id(), config);
  360. r = task->advance();
  361. CHECK(std::get_if<bool>(&r));
  362. CHECK(*std::get_if<bool>(&r) == true);
  363. r = task->advance();
  364. REQUIRE(std::get_if<changed_meta_t>(&r));
  365. auto ref = std::get_if<changed_meta_t>(&r);
  366. CHECK(ref->file == file);
  367. }
  368. r = task->advance();
  369. CHECK(std::get_if<bool>(&r));
  370. CHECK(*std::get_if<bool>(&r) == false);
  371. }
  372. SECTION("tmp") {
  373. pr_file.set_block_size(5);
  374. pr_file.set_size(5);
  375. pr_file.set_modified_s(modified);
  376. auto path = root_path / "a.txt.syncspirit-tmp";
  377. SECTION("size match -> ok, will recalc") {
  378. write_file(path, "12345");
  379. auto file_peer = file_info_t::create(sequencer->next_uuid(), pr_file, folder_peer).value();
  380. REQUIRE(folder_peer->add_strict(file_peer));
  381. auto task = scan_task_t(cluster, folder->get_id(), config);
  382. auto r = task.advance();
  383. CHECK(std::get_if<bool>(&r));
  384. CHECK(*std::get_if<bool>(&r) == true);
  385. r = task.advance();
  386. REQUIRE(std::get_if<incomplete_t>(&r));
  387. auto ref = std::get_if<incomplete_t>(&r);
  388. CHECK(ref->file);
  389. CHECK(ref->opened_file);
  390. r = task.advance();
  391. CHECK(std::get_if<bool>(&r));
  392. CHECK(*std::get_if<bool>(&r) == false);
  393. }
  394. SECTION("size mismatch -> remove & ignore") {
  395. write_file(path, "123456");
  396. auto file_peer = file_info_t::create(sequencer->next_uuid(), pr_file, folder_peer).value();
  397. REQUIRE(folder_peer->add_strict(file_peer));
  398. auto task = scan_task_t(cluster, folder->get_id(), config);
  399. auto r = task.advance();
  400. CHECK(std::get_if<bool>(&r));
  401. CHECK(*std::get_if<bool>(&r) == true);
  402. r = task.advance();
  403. CHECK(std::get_if<incomplete_removed_t>(&r));
  404. CHECK(std::get_if<incomplete_removed_t>(&r)->file == file_peer);
  405. r = task.advance();
  406. CHECK(std::get_if<bool>(&r));
  407. CHECK(*std::get_if<bool>(&r) == false);
  408. CHECK(!bfs::exists(path));
  409. }
  410. SECTION("size mismatch for global source -> remove & ignore") {
  411. write_file(path, "123456");
  412. auto file_peer = file_info_t::create(sequencer->next_uuid(), pr_file, folder_peer).value();
  413. REQUIRE(folder_peer->add_strict(file_peer));
  414. pr_file.set_size(file_peer->get_size() + 10);
  415. auto c2 = version->add_counters();
  416. c2->set_id(peer2_device->device_id().get_uint());
  417. c2->set_value(2);
  418. auto file_peer2 = file_info_t::create(sequencer->next_uuid(), pr_file, folder_peer2).value();
  419. REQUIRE(folder_peer2->add_strict(file_peer2));
  420. auto task = scan_task_t(cluster, folder->get_id(), config);
  421. auto r = task.advance();
  422. CHECK(std::get_if<bool>(&r));
  423. CHECK(*std::get_if<bool>(&r) == true);
  424. r = task.advance();
  425. CHECK(std::get_if<incomplete_removed_t>(&r));
  426. CHECK(std::get_if<incomplete_removed_t>(&r)->file == file_peer2);
  427. r = task.advance();
  428. CHECK(std::get_if<bool>(&r));
  429. CHECK(*std::get_if<bool>(&r) == false);
  430. CHECK(!bfs::exists(path));
  431. }
  432. SECTION("no source -> remove") {
  433. write_file(path, "123456");
  434. auto task = scan_task_t(cluster, folder->get_id(), config);
  435. auto r = task.advance();
  436. CHECK(std::get_if<bool>(&r));
  437. CHECK(*std::get_if<bool>(&r) == true);
  438. r = task.advance();
  439. CHECK(std::get_if<orphaned_removed_t>(&r));
  440. CHECK(std::get_if<orphaned_removed_t>(&r)->path == path);
  441. r = task.advance();
  442. CHECK(std::get_if<bool>(&r));
  443. CHECK(*std::get_if<bool>(&r) == false);
  444. CHECK(!bfs::exists(path));
  445. }
  446. }
  447. SECTION("tmp & non-tmp: both are returned") {
  448. pr_file.set_block_size(5);
  449. pr_file.set_size(5);
  450. pr_file.set_modified_s(modified);
  451. auto path = root_path / "a.txt";
  452. auto path_tmp = root_path / "a.txt.syncspirit-tmp";
  453. write_file(path, "12345");
  454. write_file(path_tmp, "12345");
  455. bfs::last_write_time(path, modified);
  456. auto status = bfs::status(path);
  457. pr_file.set_permissions(static_cast<uint32_t>(status.permissions()));
  458. auto file_my = file_info_t::create(sequencer->next_uuid(), pr_file, folder_my).value();
  459. counter->set_id(10);
  460. auto file_peer = file_info_t::create(sequencer->next_uuid(), pr_file, folder_peer).value();
  461. REQUIRE(folder_my->add_strict(file_my));
  462. REQUIRE(folder_peer->add_strict(file_peer));
  463. auto task = scan_task_t(cluster, folder->get_id(), config);
  464. auto r = task.advance();
  465. CHECK(std::get_if<bool>(&r));
  466. CHECK(*std::get_if<bool>(&r) == true);
  467. unchanged_meta_t unchanged;
  468. incomplete_t incomplete;
  469. for (int i = 0; i < 2; ++i) {
  470. r = task.advance();
  471. std::visit(
  472. [&](auto &&it) {
  473. using T = std::decay_t<decltype(it)>;
  474. if constexpr (std::is_same_v<T, unchanged_meta_t>) {
  475. unchanged = it;
  476. } else if constexpr (std::is_same_v<T, incomplete_t>) {
  477. incomplete = it;
  478. } else {
  479. REQUIRE((0 && "unexpected result"));
  480. }
  481. },
  482. r);
  483. }
  484. CHECK(unchanged.file == file_my);
  485. CHECK(incomplete.file);
  486. CHECK(incomplete.opened_file);
  487. r = task.advance();
  488. CHECK(std::get_if<bool>(&r));
  489. CHECK(*std::get_if<bool>(&r) == false);
  490. }
  491. SECTION("cannot read file error") {
  492. pr_file.set_name("a.txt");
  493. auto path = root_path / "a.txt";
  494. write_file(path, "12345");
  495. auto file = file_info_t::create(sequencer->next_uuid(), pr_file, folder_my).value();
  496. REQUIRE(folder_my->add_strict(file));
  497. auto task = scan_task_t(cluster, folder->get_id(), config);
  498. auto r = task.advance();
  499. CHECK(std::get_if<bool>(&r));
  500. CHECK(*std::get_if<bool>(&r) == true);
  501. bfs::remove(path);
  502. r = task.advance();
  503. REQUIRE(std::get_if<file_error_t>(&r));
  504. auto err = std::get_if<file_error_t>(&r);
  505. REQUIRE(err->path == path);
  506. REQUIRE(err->ec);
  507. r = task.advance();
  508. CHECK(std::get_if<bool>(&r));
  509. CHECK(*std::get_if<bool>(&r) == false);
  510. }
  511. SECTION("cannot read dir, error") {
  512. pr_file.set_name("some/a.txt");
  513. auto path = root_path / "some" / "a.txt";
  514. auto parent = path.parent_path();
  515. write_file(path, "12345");
  516. sys::error_code ec;
  517. bfs::permissions(parent, bfs::perms::no_perms, ec);
  518. bfs::permissions(path, bfs::perms::owner_read, ec);
  519. if (ec) {
  520. auto file = file_info_t::create(sequencer->next_uuid(), pr_file, folder_my).value();
  521. REQUIRE(folder_my->add_strict(file));
  522. auto task = scan_task_t(cluster, folder->get_id(), config);
  523. auto r = task.advance();
  524. CHECK(std::get_if<bool>(&r));
  525. CHECK(*std::get_if<bool>(&r) == true);
  526. r = task.advance();
  527. auto *uf = std::get_if<unknown_file_t>(&r);
  528. REQUIRE(uf);
  529. CHECK(uf->path.filename() == "some");
  530. CHECK(uf->metadata.size() == 0);
  531. CHECK(uf->metadata.type() == proto::FileInfoType::DIRECTORY);
  532. r = task.advance();
  533. REQUIRE(std::get_if<scan_errors_t>(&r));
  534. auto errs = std::get_if<scan_errors_t>(&r);
  535. REQUIRE(errs);
  536. REQUIRE(errs->size() == 1);
  537. REQUIRE(errs->at(0).path == parent);
  538. REQUIRE(errs->at(0).ec);
  539. r = task.advance();
  540. REQUIRE(std::get_if<bool>(&r));
  541. CHECK(*std::get_if<bool>(&r) == false);
  542. bfs::permissions(parent, bfs::perms::all_all);
  543. }
  544. }
  545. }
  546. SECTION("symlink file") {
  547. auto modified = std::time_t{1642007468};
  548. auto pr_file = proto::FileInfo{};
  549. pr_file.set_name("a.txt");
  550. pr_file.set_sequence(4);
  551. pr_file.set_type(proto::FileInfoType::SYMLINK);
  552. pr_file.set_symlink_target("b.txt");
  553. auto version = pr_file.mutable_version();
  554. auto counter = version->add_counters();
  555. counter->set_id(1);
  556. counter->set_value(peer_device->device_id().get_uint());
  557. SECTION("symlink does not exists") {
  558. pr_file.set_modified_s(modified);
  559. auto path = root_path / "a.txt";
  560. auto target = bfs::path("b.txt");
  561. bfs::create_symlink(target, path);
  562. auto file = file_info_t::create(sequencer->next_uuid(), pr_file, folder_my).value();
  563. REQUIRE(folder_my->add_strict(file));
  564. auto task = scan_task_t(cluster, folder->get_id(), config);
  565. auto r = task.advance();
  566. CHECK(std::get_if<bool>(&r));
  567. CHECK(*std::get_if<bool>(&r) == true);
  568. r = task.advance();
  569. REQUIRE(std::get_if<unchanged_meta_t>(&r));
  570. auto ref = std::get_if<unchanged_meta_t>(&r);
  571. CHECK(ref->file == file);
  572. r = task.advance();
  573. CHECK(std::get_if<bool>(&r));
  574. CHECK(*std::get_if<bool>(&r) == false);
  575. }
  576. SECTION("symlink does exists") {
  577. pr_file.set_modified_s(modified);
  578. pr_file.set_symlink_target("b");
  579. auto path = root_path / "a.txt";
  580. auto target = bfs::path("b");
  581. bfs::create_symlink(target, path);
  582. bfs::create_directories(root_path / target);
  583. auto pr_dir = proto::FileInfo{};
  584. pr_dir.set_name("b");
  585. pr_dir.set_sequence(pr_file.sequence() + 1);
  586. pr_dir.set_type(proto::FileInfoType::DIRECTORY);
  587. *pr_dir.mutable_version() = pr_file.version();
  588. auto file = file_info_t::create(sequencer->next_uuid(), pr_file, folder_my).value();
  589. auto dir = file_info_t::create(sequencer->next_uuid(), pr_dir, folder_my).value();
  590. REQUIRE(folder_my->add_strict(file));
  591. REQUIRE(folder_my->add_strict(dir));
  592. auto task = scan_task_t(cluster, folder->get_id(), config);
  593. auto r = task.advance();
  594. CHECK(std::get_if<bool>(&r));
  595. CHECK(*std::get_if<bool>(&r) == true);
  596. r = task.advance();
  597. REQUIRE(std::get_if<unchanged_meta_t>(&r));
  598. auto ref = std::get_if<unchanged_meta_t>(&r);
  599. CHECK(((ref->file == dir) || (ref->file == file)));
  600. r = task.advance();
  601. REQUIRE(std::get_if<unchanged_meta_t>(&r));
  602. ref = std::get_if<unchanged_meta_t>(&r);
  603. CHECK(((ref->file == dir) || (ref->file == file)));
  604. r = task.advance();
  605. CHECK(std::get_if<bool>(&r));
  606. CHECK(*std::get_if<bool>(&r) == true);
  607. r = task.advance();
  608. CHECK(std::get_if<bool>(&r));
  609. CHECK(*std::get_if<bool>(&r) == false);
  610. }
  611. SECTION("symlink to root") {
  612. pr_file.set_modified_s(modified);
  613. pr_file.set_symlink_target("/");
  614. auto path = root_path / "a.txt";
  615. auto target = bfs::path("/");
  616. bfs::create_symlink(target, path);
  617. auto file = file_info_t::create(sequencer->next_uuid(), pr_file, folder_my).value();
  618. REQUIRE(folder_my->add_strict(file));
  619. auto task = scan_task_t(cluster, folder->get_id(), config);
  620. auto r = task.advance();
  621. CHECK(std::get_if<bool>(&r));
  622. CHECK(*std::get_if<bool>(&r) == true);
  623. r = task.advance();
  624. REQUIRE(std::get_if<unchanged_meta_t>(&r));
  625. auto ref = std::get_if<unchanged_meta_t>(&r);
  626. CHECK(ref->file == file);
  627. r = task.advance();
  628. CHECK(std::get_if<bool>(&r));
  629. CHECK(*std::get_if<bool>(&r) == false);
  630. }
  631. SECTION("symlink points to something different") {
  632. pr_file.set_modified_s(modified);
  633. auto path = root_path / "a.txt";
  634. auto target = bfs::path("c.txt");
  635. bfs::create_symlink(target, path);
  636. auto file = file_info_t::create(sequencer->next_uuid(), pr_file, folder_my).value();
  637. REQUIRE(folder_my->add_strict(file));
  638. auto task = scan_task_t(cluster, folder->get_id(), config);
  639. auto r = task.advance();
  640. CHECK(std::get_if<bool>(&r));
  641. CHECK(*std::get_if<bool>(&r) == true);
  642. r = task.advance();
  643. REQUIRE(std::get_if<changed_meta_t>(&r));
  644. auto ref = std::get_if<changed_meta_t>(&r);
  645. CHECK(ref->file == file);
  646. r = task.advance();
  647. CHECK(std::get_if<bool>(&r));
  648. CHECK(*std::get_if<bool>(&r) == false);
  649. }
  650. }
  651. }