053-scan_task.cpp 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778
  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 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<io_errors_t>(&r));
  52. auto errs = std::get_if<io_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(2);
  128. auto version = pr_file.mutable_version();
  129. auto counter = version->add_counters();
  130. counter->set_id(1);
  131. counter->set_value(peer_device->as_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 file = file_info_t::create(sequencer->next_uuid(), pr_file, folder_my).value();
  140. folder_my->add(file, false);
  141. auto task = scan_task_t(cluster, folder->get_id(), config);
  142. auto r = task.advance();
  143. CHECK(std::get_if<bool>(&r));
  144. CHECK(*std::get_if<bool>(&r) == true);
  145. r = task.advance();
  146. REQUIRE(std::get_if<unchanged_meta_t>(&r));
  147. auto ref = std::get_if<unchanged_meta_t>(&r);
  148. CHECK(ref->file == file);
  149. r = task.advance();
  150. CHECK(std::get_if<bool>(&r));
  151. CHECK(*std::get_if<bool>(&r) == false);
  152. }
  153. SECTION("meta is not changed (dir)") {
  154. pr_file.set_name("a-dir");
  155. pr_file.set_type(proto::FileInfoType::DIRECTORY);
  156. auto dir = root_path / "a-dir";
  157. bfs::create_directories(dir);
  158. auto file = file_info_t::create(sequencer->next_uuid(), pr_file, folder_my).value();
  159. folder_my->add(file, false);
  160. auto task = scan_task_t(cluster, folder->get_id(), config);
  161. auto r = task.advance();
  162. CHECK(std::get_if<bool>(&r));
  163. CHECK(*std::get_if<bool>(&r) == true);
  164. r = task.advance();
  165. REQUIRE(std::get_if<unchanged_meta_t>(&r));
  166. auto ref = std::get_if<unchanged_meta_t>(&r);
  167. CHECK(ref->file == file);
  168. r = task.advance();
  169. CHECK(std::get_if<bool>(&r));
  170. CHECK(*std::get_if<bool>(&r) == true);
  171. r = task.advance();
  172. CHECK(std::get_if<bool>(&r));
  173. CHECK(*std::get_if<bool>(&r) == false);
  174. }
  175. SECTION("meta is not changed (dir + file inside)") {
  176. auto pr_dir = pr_file;
  177. pr_dir.set_name("a-dir-2");
  178. pr_dir.set_type(proto::FileInfoType::DIRECTORY);
  179. pr_file.set_block_size(5);
  180. pr_file.set_size(5);
  181. pr_file.set_modified_s(modified);
  182. pr_file.set_name("a-dir-2/a.txt");
  183. auto dir = root_path / "a-dir-2";
  184. bfs::create_directories(dir);
  185. auto path = root_path / "a-dir-2" / "a.txt";
  186. write_file(path, "12345");
  187. bfs::last_write_time(path, modified);
  188. auto info_dir = file_info_t::create(sequencer->next_uuid(), pr_dir, folder_my).value();
  189. folder_my->add(info_dir, false);
  190. auto info_file = file_info_t::create(sequencer->next_uuid(), pr_file, folder_my).value();
  191. folder_my->add(info_file, false);
  192. auto task = scan_task_t(cluster, folder->get_id(), config);
  193. auto r = task.advance();
  194. CHECK(std::get_if<bool>(&r));
  195. CHECK(*std::get_if<bool>(&r) == true);
  196. r = task.advance();
  197. REQUIRE(std::get_if<unchanged_meta_t>(&r));
  198. auto ref = std::get_if<unchanged_meta_t>(&r);
  199. CHECK(ref->file == info_dir);
  200. r = task.advance();
  201. CHECK(std::get_if<bool>(&r));
  202. CHECK(*std::get_if<bool>(&r) == true);
  203. r = task.advance();
  204. REQUIRE(std::get_if<unchanged_meta_t>(&r));
  205. ref = std::get_if<unchanged_meta_t>(&r);
  206. CHECK(ref->file == info_file);
  207. r = task.advance();
  208. CHECK(std::get_if<bool>(&r));
  209. CHECK(*std::get_if<bool>(&r) == false);
  210. }
  211. SECTION("file has been removed") {
  212. pr_file.set_block_size(5);
  213. pr_file.set_size(5);
  214. pr_file.set_modified_s(modified);
  215. auto file = file_info_t::create(sequencer->next_uuid(), pr_file, folder_my).value();
  216. folder_my->add(file, false);
  217. auto task = scan_task_t(cluster, folder->get_id(), config);
  218. auto r = task.advance();
  219. CHECK(std::get_if<bool>(&r));
  220. CHECK(*std::get_if<bool>(&r) == true);
  221. r = task.advance();
  222. REQUIRE(std::get_if<removed_t>(&r));
  223. auto ref = std::get_if<removed_t>(&r);
  224. CHECK(ref->file == file);
  225. r = task.advance();
  226. CHECK(std::get_if<bool>(&r));
  227. CHECK(*std::get_if<bool>(&r) == false);
  228. }
  229. SECTION("dir has been removed") {
  230. pr_file.set_name("a-dir");
  231. pr_file.set_type(proto::FileInfoType::DIRECTORY);
  232. auto file = file_info_t::create(sequencer->next_uuid(), pr_file, folder_my).value();
  233. folder_my->add(file, false);
  234. auto task = scan_task_t(cluster, folder->get_id(), config);
  235. auto r = task.advance();
  236. CHECK(std::get_if<bool>(&r));
  237. CHECK(*std::get_if<bool>(&r) == true);
  238. r = task.advance();
  239. REQUIRE(std::get_if<removed_t>(&r));
  240. auto ref = std::get_if<removed_t>(&r);
  241. CHECK(ref->file == file);
  242. r = task.advance();
  243. CHECK(std::get_if<bool>(&r));
  244. CHECK(*std::get_if<bool>(&r) == false);
  245. }
  246. SECTION("removed file does not exist => unchanged meta") {
  247. pr_file.set_deleted(true);
  248. auto file = file_info_t::create(sequencer->next_uuid(), pr_file, folder_my).value();
  249. folder_my->add(file, false);
  250. auto task = scan_task_t(cluster, folder->get_id(), config);
  251. auto r = task.advance();
  252. CHECK(std::get_if<bool>(&r));
  253. CHECK(*std::get_if<bool>(&r) == true);
  254. r = task.advance();
  255. REQUIRE(std::get_if<unchanged_meta_t>(&r));
  256. auto ref = std::get_if<unchanged_meta_t>(&r);
  257. CHECK(ref->file == file);
  258. r = task.advance();
  259. CHECK(std::get_if<bool>(&r));
  260. CHECK(*std::get_if<bool>(&r) == false);
  261. }
  262. SECTION("removed dir does not exist => unchanged meta") {
  263. pr_file.set_deleted(true);
  264. pr_file.set_type(proto::FileInfoType::DIRECTORY);
  265. auto file = file_info_t::create(sequencer->next_uuid(), pr_file, folder_my).value();
  266. folder_my->add(file, false);
  267. auto task = scan_task_t(cluster, folder->get_id(), config);
  268. auto r = task.advance();
  269. CHECK(std::get_if<bool>(&r));
  270. CHECK(*std::get_if<bool>(&r) == true);
  271. r = task.advance();
  272. REQUIRE(std::get_if<unchanged_meta_t>(&r));
  273. auto ref = std::get_if<unchanged_meta_t>(&r);
  274. CHECK(ref->file == file);
  275. r = task.advance();
  276. CHECK(std::get_if<bool>(&r));
  277. CHECK(*std::get_if<bool>(&r) == false);
  278. }
  279. SECTION("root dir does not exist & deleted file => unchanged meta") {
  280. pr_file.set_deleted(true);
  281. folder->set_path(root_path / "zzz");
  282. auto file = file_info_t::create(sequencer->next_uuid(), pr_file, folder_my).value();
  283. folder_my->add(file, false);
  284. auto task = scan_task_t(cluster, folder->get_id(), config);
  285. auto r = task.advance();
  286. REQUIRE(std::get_if<bool>(&r));
  287. CHECK(*std::get_if<bool>(&r) == true);
  288. r = task.advance();
  289. REQUIRE(std::get_if<unchanged_meta_t>(&r));
  290. auto ref = std::get_if<unchanged_meta_t>(&r);
  291. CHECK(ref->file == file);
  292. r = task.advance();
  293. CHECK(std::get_if<bool>(&r));
  294. CHECK(*std::get_if<bool>(&r) == false);
  295. }
  296. SECTION("meta is changed") {
  297. auto task = scan_task_ptr_t{};
  298. auto file = file_info_ptr_t{};
  299. auto r = scan_result_t{};
  300. SECTION("file size differs") {
  301. pr_file.set_block_size(5);
  302. pr_file.set_size(6);
  303. pr_file.set_modified_s(modified);
  304. auto path = root_path / "a.txt";
  305. write_file(path, "12345");
  306. bfs::last_write_time(path, modified);
  307. file = file_info_t::create(sequencer->next_uuid(), pr_file, folder_my).value();
  308. folder_my->add(file, false);
  309. task = new scan_task_t(cluster, folder->get_id(), config);
  310. r = task->advance();
  311. CHECK(std::get_if<bool>(&r));
  312. CHECK(*std::get_if<bool>(&r) == true);
  313. r = task->advance();
  314. REQUIRE(std::get_if<changed_meta_t>(&r));
  315. auto ref = std::get_if<changed_meta_t>(&r);
  316. CHECK(ref->file == file);
  317. CHECK(ref->metadata.size() == 5);
  318. CHECK(ref->metadata.modified_s() == modified);
  319. }
  320. SECTION("modification time differs") {
  321. pr_file.set_block_size(5);
  322. pr_file.set_size(5);
  323. pr_file.set_modified_s(modified + 1);
  324. auto path = root_path / "a.txt";
  325. write_file(path, "12345");
  326. bfs::last_write_time(path, modified);
  327. file = file_info_t::create(sequencer->next_uuid(), pr_file, folder_my).value();
  328. folder_my->add(file, false);
  329. task = new scan_task_t(cluster, folder->get_id(), config);
  330. r = task->advance();
  331. CHECK(std::get_if<bool>(&r));
  332. CHECK(*std::get_if<bool>(&r) == true);
  333. r = task->advance();
  334. REQUIRE(std::get_if<changed_meta_t>(&r));
  335. auto ref = std::get_if<changed_meta_t>(&r);
  336. CHECK(ref->file == file);
  337. CHECK(ref->metadata.size() == 5);
  338. CHECK(ref->metadata.modified_s() == modified);
  339. }
  340. r = task->advance();
  341. CHECK(std::get_if<bool>(&r));
  342. CHECK(*std::get_if<bool>(&r) == false);
  343. }
  344. SECTION("tmp") {
  345. pr_file.set_block_size(5);
  346. pr_file.set_size(5);
  347. pr_file.set_modified_s(modified);
  348. auto path = root_path / "a.txt.syncspirit-tmp";
  349. SECTION("size match -> ok, will recalc") {
  350. write_file(path, "12345");
  351. auto file_peer = file_info_t::create(sequencer->next_uuid(), pr_file, folder_peer).value();
  352. folder_peer->add(file_peer, false);
  353. auto task = scan_task_t(cluster, folder->get_id(), config);
  354. auto r = task.advance();
  355. CHECK(std::get_if<bool>(&r));
  356. CHECK(*std::get_if<bool>(&r) == true);
  357. r = task.advance();
  358. REQUIRE(std::get_if<incomplete_t>(&r));
  359. auto ref = std::get_if<incomplete_t>(&r);
  360. CHECK(ref->file);
  361. CHECK(ref->opened_file);
  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_peer = file_info_t::create(sequencer->next_uuid(), pr_file, folder_peer).value();
  369. folder_peer->add(file_peer, false);
  370. auto task = scan_task_t(cluster, folder->get_id(), config);
  371. auto r = task.advance();
  372. CHECK(std::get_if<bool>(&r));
  373. CHECK(*std::get_if<bool>(&r) == true);
  374. r = task.advance();
  375. CHECK(std::get_if<incomplete_removed_t>(&r));
  376. CHECK(std::get_if<incomplete_removed_t>(&r)->file == file_peer);
  377. r = task.advance();
  378. CHECK(std::get_if<bool>(&r));
  379. CHECK(*std::get_if<bool>(&r) == false);
  380. CHECK(!bfs::exists(path));
  381. }
  382. SECTION("size mismatch for global source -> remove & ignore") {
  383. write_file(path, "123456");
  384. auto file_peer = file_info_t::create(sequencer->next_uuid(), pr_file, folder_peer).value();
  385. folder_peer->add(file_peer, false);
  386. pr_file.set_size(file_peer->get_size() + 10);
  387. auto c2 = version->add_counters();
  388. c2->set_id(peer2_device->as_uint());
  389. c2->set_value(2);
  390. auto file_peer2 = file_info_t::create(sequencer->next_uuid(), pr_file, folder_peer2).value();
  391. folder_peer2->add(file_peer2, false);
  392. auto task = scan_task_t(cluster, folder->get_id(), config);
  393. auto r = task.advance();
  394. CHECK(std::get_if<bool>(&r));
  395. CHECK(*std::get_if<bool>(&r) == true);
  396. r = task.advance();
  397. CHECK(std::get_if<incomplete_removed_t>(&r));
  398. CHECK(std::get_if<incomplete_removed_t>(&r)->file == file_peer2);
  399. r = task.advance();
  400. CHECK(std::get_if<bool>(&r));
  401. CHECK(*std::get_if<bool>(&r) == false);
  402. CHECK(!bfs::exists(path));
  403. }
  404. SECTION("no source -> remove") {
  405. write_file(path, "123456");
  406. auto task = scan_task_t(cluster, folder->get_id(), config);
  407. auto r = task.advance();
  408. CHECK(std::get_if<bool>(&r));
  409. CHECK(*std::get_if<bool>(&r) == true);
  410. r = task.advance();
  411. CHECK(std::get_if<orphaned_removed_t>(&r));
  412. CHECK(std::get_if<orphaned_removed_t>(&r)->path == path);
  413. r = task.advance();
  414. CHECK(std::get_if<bool>(&r));
  415. CHECK(*std::get_if<bool>(&r) == false);
  416. CHECK(!bfs::exists(path));
  417. }
  418. }
  419. SECTION("tmp & non-tmp: both are returned") {
  420. pr_file.set_block_size(5);
  421. pr_file.set_size(5);
  422. pr_file.set_modified_s(modified);
  423. auto file_my = file_info_t::create(sequencer->next_uuid(), pr_file, folder_my).value();
  424. counter->set_id(10);
  425. auto file_peer = file_info_t::create(sequencer->next_uuid(), pr_file, folder_peer).value();
  426. folder_my->add(file_my, false);
  427. folder_peer->add(file_peer, false);
  428. auto path = root_path / "a.txt";
  429. auto path_tmp = root_path / "a.txt.syncspirit-tmp";
  430. write_file(path, "12345");
  431. write_file(path_tmp, "12345");
  432. bfs::last_write_time(path, modified);
  433. auto task = scan_task_t(cluster, folder->get_id(), config);
  434. auto r = task.advance();
  435. CHECK(std::get_if<bool>(&r));
  436. CHECK(*std::get_if<bool>(&r) == true);
  437. unchanged_meta_t unchanged;
  438. incomplete_t incomplete;
  439. for (int i = 0; i < 2; ++i) {
  440. r = task.advance();
  441. std::visit(
  442. [&](auto &&it) {
  443. using T = std::decay_t<decltype(it)>;
  444. if constexpr (std::is_same_v<T, unchanged_meta_t>) {
  445. unchanged = it;
  446. } else if constexpr (std::is_same_v<T, incomplete_t>) {
  447. incomplete = it;
  448. } else {
  449. REQUIRE((0 && "unexpected result"));
  450. }
  451. },
  452. r);
  453. }
  454. CHECK(unchanged.file == file_my);
  455. CHECK(incomplete.file);
  456. CHECK(incomplete.opened_file);
  457. r = task.advance();
  458. CHECK(std::get_if<bool>(&r));
  459. CHECK(*std::get_if<bool>(&r) == false);
  460. }
  461. SECTION("cannot read file error") {
  462. pr_file.set_name("a.txt");
  463. auto path = root_path / "a.txt";
  464. write_file(path, "12345");
  465. auto file = file_info_t::create(sequencer->next_uuid(), pr_file, folder_my).value();
  466. folder_my->add(file, false);
  467. auto task = scan_task_t(cluster, folder->get_id(), config);
  468. auto r = task.advance();
  469. CHECK(std::get_if<bool>(&r));
  470. CHECK(*std::get_if<bool>(&r) == true);
  471. bfs::remove(path);
  472. r = task.advance();
  473. REQUIRE(std::get_if<file_error_t>(&r));
  474. auto err = std::get_if<file_error_t>(&r);
  475. REQUIRE(err->path == path);
  476. REQUIRE(err->ec);
  477. r = task.advance();
  478. CHECK(std::get_if<bool>(&r));
  479. CHECK(*std::get_if<bool>(&r) == false);
  480. }
  481. SECTION("cannot read dir, error") {
  482. pr_file.set_name("some/a.txt");
  483. auto path = root_path / "some" / "a.txt";
  484. auto parent = path.parent_path();
  485. write_file(path, "12345");
  486. sys::error_code ec;
  487. bfs::permissions(parent, bfs::perms::no_perms, ec);
  488. bfs::permissions(path, bfs::perms::owner_read, ec);
  489. if (ec) {
  490. auto file = file_info_t::create(sequencer->next_uuid(), pr_file, folder_my).value();
  491. folder_my->add(file, false);
  492. auto task = scan_task_t(cluster, folder->get_id(), config);
  493. auto r = task.advance();
  494. CHECK(std::get_if<bool>(&r));
  495. CHECK(*std::get_if<bool>(&r) == true);
  496. r = task.advance();
  497. auto *uf = std::get_if<unknown_file_t>(&r);
  498. REQUIRE(uf);
  499. CHECK(uf->path.filename() == "some");
  500. CHECK(uf->metadata.size() == 0);
  501. CHECK(uf->metadata.type() == proto::FileInfoType::DIRECTORY);
  502. r = task.advance();
  503. REQUIRE(std::get_if<scan_errors_t>(&r));
  504. auto errs = std::get_if<scan_errors_t>(&r);
  505. REQUIRE(errs);
  506. REQUIRE(errs->size() == 1);
  507. REQUIRE(errs->at(0).path == parent);
  508. REQUIRE(errs->at(0).ec);
  509. r = task.advance();
  510. REQUIRE(std::get_if<bool>(&r));
  511. CHECK(*std::get_if<bool>(&r) == false);
  512. bfs::permissions(parent, bfs::perms::all_all);
  513. }
  514. }
  515. }
  516. SECTION("symlink file") {
  517. auto modified = std::time_t{1642007468};
  518. auto pr_file = proto::FileInfo{};
  519. pr_file.set_name("a.txt");
  520. pr_file.set_sequence(2);
  521. pr_file.set_type(proto::FileInfoType::SYMLINK);
  522. pr_file.set_symlink_target("b.txt");
  523. auto version = pr_file.mutable_version();
  524. auto counter = version->add_counters();
  525. counter->set_id(1);
  526. counter->set_value(peer_device->as_uint());
  527. SECTION("symlink does not exists") {
  528. pr_file.set_modified_s(modified);
  529. auto path = root_path / "a.txt";
  530. auto target = bfs::path("b.txt");
  531. bfs::create_symlink(target, path);
  532. auto file = file_info_t::create(sequencer->next_uuid(), pr_file, folder_my).value();
  533. folder_my->add(file, false);
  534. auto task = scan_task_t(cluster, folder->get_id(), config);
  535. auto r = task.advance();
  536. CHECK(std::get_if<bool>(&r));
  537. CHECK(*std::get_if<bool>(&r) == true);
  538. r = task.advance();
  539. REQUIRE(std::get_if<unchanged_meta_t>(&r));
  540. auto 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) == false);
  545. }
  546. SECTION("symlink does exists") {
  547. pr_file.set_modified_s(modified);
  548. pr_file.set_symlink_target("b");
  549. auto path = root_path / "a.txt";
  550. auto target = bfs::path("b");
  551. bfs::create_symlink(target, path);
  552. bfs::create_directories(root_path / target);
  553. auto pr_dir = proto::FileInfo{};
  554. pr_dir.set_name("b");
  555. pr_dir.set_sequence(3);
  556. pr_dir.set_type(proto::FileInfoType::DIRECTORY);
  557. *pr_dir.mutable_version() = pr_file.version();
  558. auto file = file_info_t::create(sequencer->next_uuid(), pr_file, folder_my).value();
  559. auto dir = file_info_t::create(sequencer->next_uuid(), pr_dir, folder_my).value();
  560. folder_my->add(file, false);
  561. folder_my->add(dir, false);
  562. auto task = scan_task_t(cluster, folder->get_id(), config);
  563. auto r = task.advance();
  564. CHECK(std::get_if<bool>(&r));
  565. CHECK(*std::get_if<bool>(&r) == true);
  566. r = task.advance();
  567. REQUIRE(std::get_if<unchanged_meta_t>(&r));
  568. auto ref = std::get_if<unchanged_meta_t>(&r);
  569. CHECK(ref->file == dir);
  570. r = task.advance();
  571. REQUIRE(std::get_if<unchanged_meta_t>(&r));
  572. ref = std::get_if<unchanged_meta_t>(&r);
  573. CHECK(ref->file == file);
  574. r = task.advance();
  575. CHECK(std::get_if<bool>(&r));
  576. CHECK(*std::get_if<bool>(&r) == true);
  577. r = task.advance();
  578. CHECK(std::get_if<bool>(&r));
  579. CHECK(*std::get_if<bool>(&r) == false);
  580. }
  581. SECTION("symlink to root") {
  582. pr_file.set_modified_s(modified);
  583. pr_file.set_symlink_target("/");
  584. auto path = root_path / "a.txt";
  585. auto target = bfs::path("/");
  586. bfs::create_symlink(target, path);
  587. auto file = file_info_t::create(sequencer->next_uuid(), pr_file, folder_my).value();
  588. folder_my->add(file, false);
  589. auto task = scan_task_t(cluster, folder->get_id(), config);
  590. auto r = task.advance();
  591. CHECK(std::get_if<bool>(&r));
  592. CHECK(*std::get_if<bool>(&r) == true);
  593. r = task.advance();
  594. REQUIRE(std::get_if<unchanged_meta_t>(&r));
  595. auto ref = std::get_if<unchanged_meta_t>(&r);
  596. CHECK(ref->file == file);
  597. r = task.advance();
  598. CHECK(std::get_if<bool>(&r));
  599. CHECK(*std::get_if<bool>(&r) == false);
  600. }
  601. SECTION("symlink points to something different") {
  602. pr_file.set_modified_s(modified);
  603. auto path = root_path / "a.txt";
  604. auto target = bfs::path("c.txt");
  605. bfs::create_symlink(target, path);
  606. auto file = file_info_t::create(sequencer->next_uuid(), pr_file, folder_my).value();
  607. folder_my->add(file, false);
  608. auto task = scan_task_t(cluster, folder->get_id(), config);
  609. auto r = task.advance();
  610. CHECK(std::get_if<bool>(&r));
  611. CHECK(*std::get_if<bool>(&r) == true);
  612. r = task.advance();
  613. REQUIRE(std::get_if<changed_meta_t>(&r));
  614. auto ref = std::get_if<changed_meta_t>(&r);
  615. CHECK(ref->file == file);
  616. r = task.advance();
  617. CHECK(std::get_if<bool>(&r));
  618. CHECK(*std::get_if<bool>(&r) == false);
  619. }
  620. }
  621. }