053-scan_task.cpp 27 KB

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