fake_drivefs.cc 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571
  1. // Copyright 2018 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "ash/components/drivefs/fake_drivefs.h"
  5. #include <algorithm>
  6. #include <tuple>
  7. #include <utility>
  8. #include <vector>
  9. #include "ash/components/drivefs/drivefs_util.h"
  10. #include "ash/components/drivefs/mojom/drivefs.mojom.h"
  11. #include "base/bind.h"
  12. #include "base/containers/contains.h"
  13. #include "base/containers/cxx20_erase.h"
  14. #include "base/files/file.h"
  15. #include "base/files/file_enumerator.h"
  16. #include "base/files/file_util.h"
  17. #include "base/no_destructor.h"
  18. #include "base/numerics/safe_conversions.h"
  19. #include "base/strings/strcat.h"
  20. #include "base/strings/string_util.h"
  21. #include "base/task/thread_pool.h"
  22. #include "base/threading/thread_restrictions.h"
  23. #include "chromeos/ash/components/dbus/cros_disks/cros_disks_client.h"
  24. #include "chromeos/ash/components/dbus/cros_disks/fake_cros_disks_client.h"
  25. #include "mojo/public/cpp/bindings/pending_remote.h"
  26. #include "mojo/public/cpp/bindings/remote.h"
  27. #include "mojo/public/cpp/bindings/self_owned_receiver.h"
  28. #include "net/base/mime_util.h"
  29. #include "url/gurl.h"
  30. namespace drivefs {
  31. namespace {
  32. std::vector<std::pair<base::RepeatingCallback<std::string()>,
  33. base::WeakPtr<FakeDriveFs>>>&
  34. GetRegisteredFakeDriveFsIntances() {
  35. static base::NoDestructor<std::vector<std::pair<
  36. base::RepeatingCallback<std::string()>, base::WeakPtr<FakeDriveFs>>>>
  37. registered_fake_drivefs_instances;
  38. return *registered_fake_drivefs_instances;
  39. }
  40. base::FilePath MaybeMountDriveFs(
  41. const std::string& source_path,
  42. const std::vector<std::string>& mount_options) {
  43. GURL source_url(source_path);
  44. DCHECK(source_url.is_valid());
  45. if (source_url.scheme() != "drivefs") {
  46. return {};
  47. }
  48. std::string datadir_suffix;
  49. for (const auto& option : mount_options) {
  50. if (base::StartsWith(option, "datadir=", base::CompareCase::SENSITIVE)) {
  51. auto datadir =
  52. base::FilePath(base::StringPiece(option).substr(strlen("datadir=")));
  53. CHECK(datadir.IsAbsolute());
  54. CHECK(!datadir.ReferencesParent());
  55. datadir_suffix = datadir.BaseName().value();
  56. break;
  57. }
  58. }
  59. CHECK(!datadir_suffix.empty());
  60. for (auto& registration : GetRegisteredFakeDriveFsIntances()) {
  61. std::string account_id = registration.first.Run();
  62. if (registration.second && !account_id.empty() &&
  63. account_id == datadir_suffix) {
  64. return registration.second->mount_path();
  65. }
  66. }
  67. NOTREACHED() << datadir_suffix;
  68. return {};
  69. }
  70. } // namespace
  71. FakeDriveFsBootstrapListener::FakeDriveFsBootstrapListener(
  72. mojo::PendingRemote<drivefs::mojom::DriveFsBootstrap> bootstrap)
  73. : bootstrap_(std::move(bootstrap)) {}
  74. FakeDriveFsBootstrapListener::~FakeDriveFsBootstrapListener() = default;
  75. void FakeDriveFsBootstrapListener::SendInvitationOverPipe(base::ScopedFD) {}
  76. mojo::PendingRemote<mojom::DriveFsBootstrap>
  77. FakeDriveFsBootstrapListener::bootstrap() {
  78. return std::move(bootstrap_);
  79. }
  80. struct FakeDriveFs::FileMetadata {
  81. std::string mime_type;
  82. bool pinned = false;
  83. bool hosted = false;
  84. bool shared = false;
  85. std::string original_name;
  86. mojom::Capabilities capabilities;
  87. mojom::FolderFeature folder_feature;
  88. std::string doc_id;
  89. int64_t stable_id = 0;
  90. std::string alternate_url;
  91. };
  92. class FakeDriveFs::SearchQuery : public mojom::SearchQuery {
  93. public:
  94. SearchQuery(base::WeakPtr<FakeDriveFs> drive_fs,
  95. drivefs::mojom::QueryParametersPtr params)
  96. : drive_fs_(std::move(drive_fs)), params_(std::move(params)) {}
  97. SearchQuery(const SearchQuery&) = delete;
  98. SearchQuery& operator=(const SearchQuery&) = delete;
  99. private:
  100. void GetNextPage(GetNextPageCallback callback) override {
  101. if (!drive_fs_) {
  102. std::move(callback).Run(drive::FileError::FILE_ERROR_ABORT, {});
  103. } else {
  104. // Default implementation: just search for a file name.
  105. callback_ = std::move(callback);
  106. base::ThreadPool::PostTaskAndReplyWithResult(
  107. FROM_HERE, {base::MayBlock(), base::TaskPriority::BEST_EFFORT},
  108. base::BindOnce(&SearchQuery::SearchFiles, drive_fs_->mount_path()),
  109. base::BindOnce(&SearchQuery::GetMetadata,
  110. weak_ptr_factory_.GetWeakPtr()));
  111. }
  112. }
  113. static std::vector<drivefs::mojom::QueryItemPtr> SearchFiles(
  114. const base::FilePath& mount_path) {
  115. std::vector<drivefs::mojom::QueryItemPtr> results;
  116. base::FileEnumerator walker(
  117. mount_path, true,
  118. base::FileEnumerator::FILES | base::FileEnumerator::DIRECTORIES);
  119. for (auto file = walker.Next(); !file.empty(); file = walker.Next()) {
  120. auto item = drivefs::mojom::QueryItem::New();
  121. item->path = base::FilePath("/");
  122. CHECK(mount_path.AppendRelativePath(file, &item->path));
  123. results.push_back(std::move(item));
  124. }
  125. return results;
  126. }
  127. void GetMetadata(std::vector<drivefs::mojom::QueryItemPtr> results) {
  128. if (!drive_fs_) {
  129. std::move(callback_).Run(drive::FileError::FILE_ERROR_ABORT, {});
  130. } else {
  131. results_ = std::move(results);
  132. pending_callbacks_ = results_.size() + 1;
  133. for (size_t i = 0; i < results_.size(); ++i) {
  134. drive_fs_->GetMetadata(
  135. results_[i]->path,
  136. base::BindOnce(&SearchQuery::OnMetadata,
  137. weak_ptr_factory_.GetWeakPtr(), i));
  138. }
  139. OnComplete();
  140. }
  141. }
  142. void OnMetadata(size_t index,
  143. drive::FileError error,
  144. drivefs::mojom::FileMetadataPtr metadata) {
  145. if (error == drive::FileError::FILE_ERROR_OK) {
  146. results_[index]->metadata = std::move(metadata);
  147. }
  148. OnComplete();
  149. }
  150. void OnComplete() {
  151. if (--pending_callbacks_ == 0) {
  152. auto query = base::ToLowerASCII(
  153. params_->title.value_or(params_->text_content.value_or("")));
  154. std::vector<std::string> mime_types;
  155. if (params_->mime_types.has_value()) {
  156. mime_types = params_->mime_types.value();
  157. }
  158. if (params_->mime_type.has_value()) {
  159. mime_types.emplace_back(params_->mime_type.value() + "/*");
  160. }
  161. // Filter out non-matching results.
  162. base::EraseIf(results_, [=](const auto& item_ptr) {
  163. if (!item_ptr->metadata) {
  164. return true;
  165. }
  166. const base::FilePath path = item_ptr->path;
  167. const drivefs::mojom::FileMetadata* metadata = item_ptr->metadata.get();
  168. if (!query.empty()) {
  169. return base::ToLowerASCII(path.BaseName().value()).find(query) ==
  170. std::string::npos;
  171. }
  172. if (params_->available_offline) {
  173. return !metadata->available_offline && IsLocal(metadata->type);
  174. }
  175. if (params_->shared_with_me) {
  176. return !metadata->shared;
  177. }
  178. if (!mime_types.empty()) {
  179. std::string content_mime_type = metadata->content_mime_type;
  180. if (content_mime_type.empty()) {
  181. return true;
  182. }
  183. const auto find_mime_type_iter = std::find_if(
  184. mime_types.begin(), mime_types.end(),
  185. [content_mime_type](const std::string& mime_type) {
  186. return net::MatchesMimeType(mime_type, content_mime_type);
  187. });
  188. if (find_mime_type_iter == mime_types.end()) {
  189. return true;
  190. }
  191. }
  192. return false;
  193. });
  194. const auto sort_direction = params_->sort_direction;
  195. switch (params_->sort_field) {
  196. case mojom::QueryParameters::SortField::kLastModified:
  197. case mojom::QueryParameters::SortField::kLastViewedByMe:
  198. std::sort(
  199. results_.begin(), results_.end(),
  200. [sort_direction](const auto& a, const auto& b) {
  201. auto a_fields = std::tie(a->metadata->last_viewed_by_me_time,
  202. a->metadata->modification_time);
  203. auto b_fields = std::tie(b->metadata->last_viewed_by_me_time,
  204. b->metadata->modification_time);
  205. if (sort_direction ==
  206. mojom::QueryParameters::SortDirection::kAscending) {
  207. return a_fields < b_fields;
  208. }
  209. return b_fields < a_fields;
  210. });
  211. break;
  212. case mojom::QueryParameters::SortField::kFileSize:
  213. NOTIMPLEMENTED();
  214. break;
  215. case mojom::QueryParameters::SortField::kNone:
  216. break;
  217. }
  218. auto page_size = base::saturated_cast<size_t>(params_->page_size);
  219. if (results_.size() > page_size) {
  220. results_.resize(page_size);
  221. }
  222. std::move(callback_).Run(drive::FileError::FILE_ERROR_OK,
  223. {std::move(results_)});
  224. }
  225. }
  226. base::WeakPtr<FakeDriveFs> drive_fs_;
  227. mojom::QueryParametersPtr params_;
  228. GetNextPageCallback callback_;
  229. std::vector<drivefs::mojom::QueryItemPtr> results_;
  230. size_t pending_callbacks_ = 0;
  231. base::WeakPtrFactory<SearchQuery> weak_ptr_factory_{this};
  232. };
  233. FakeDriveFs::FakeDriveFs(const base::FilePath& mount_path)
  234. : mount_path_(mount_path) {
  235. CHECK(mount_path.IsAbsolute());
  236. CHECK(!mount_path.ReferencesParent());
  237. }
  238. FakeDriveFs::~FakeDriveFs() = default;
  239. void FakeDriveFs::RegisterMountingForAccountId(
  240. base::RepeatingCallback<std::string()> account_id_getter) {
  241. static_cast<ash::FakeCrosDisksClient*>(ash::CrosDisksClient::Get())
  242. ->AddCustomMountPointCallback(base::BindRepeating(&MaybeMountDriveFs));
  243. GetRegisteredFakeDriveFsIntances().emplace_back(std::move(account_id_getter),
  244. weak_factory_.GetWeakPtr());
  245. }
  246. std::unique_ptr<drivefs::DriveFsBootstrapListener>
  247. FakeDriveFs::CreateMojoListener() {
  248. delegate_.reset();
  249. pending_delegate_receiver_ = delegate_.BindNewPipeAndPassReceiver();
  250. delegate_->OnMounted();
  251. bootstrap_receiver_.reset();
  252. return std::make_unique<FakeDriveFsBootstrapListener>(
  253. bootstrap_receiver_.BindNewPipeAndPassRemote());
  254. }
  255. void FakeDriveFs::SetMetadata(const base::FilePath& path,
  256. const std::string& mime_type,
  257. const std::string& original_name,
  258. bool pinned,
  259. bool shared,
  260. const mojom::Capabilities& capabilities,
  261. const mojom::FolderFeature& folder_feature,
  262. const std::string& doc_id,
  263. const std::string& alternate_url) {
  264. auto& stored_metadata = metadata_[path];
  265. stored_metadata.mime_type = mime_type;
  266. stored_metadata.original_name = original_name;
  267. stored_metadata.hosted = (original_name != path.BaseName().value());
  268. stored_metadata.capabilities = capabilities;
  269. stored_metadata.folder_feature = folder_feature;
  270. stored_metadata.doc_id = doc_id;
  271. if (pinned) {
  272. stored_metadata.pinned = true;
  273. }
  274. if (shared) {
  275. stored_metadata.shared = true;
  276. }
  277. stored_metadata.alternate_url = alternate_url;
  278. }
  279. void FakeDriveFs::DisplayConfirmDialog(
  280. drivefs::mojom::DialogReasonPtr reason,
  281. drivefs::mojom::DriveFsDelegate::DisplayConfirmDialogCallback callback) {
  282. DCHECK(delegate_);
  283. delegate_->DisplayConfirmDialog(std::move(reason), std::move(callback));
  284. }
  285. void FakeDriveFs::Init(
  286. drivefs::mojom::DriveFsConfigurationPtr config,
  287. mojo::PendingReceiver<drivefs::mojom::DriveFs> receiver,
  288. mojo::PendingRemote<drivefs::mojom::DriveFsDelegate> delegate) {
  289. mojo::FusePipes(std::move(pending_delegate_receiver_), std::move(delegate));
  290. receiver_.reset();
  291. receiver_.Bind(std::move(receiver));
  292. }
  293. void FakeDriveFs::GetMetadata(const base::FilePath& path,
  294. GetMetadataCallback callback) {
  295. base::FilePath absolute_path = mount_path_;
  296. CHECK(base::FilePath("/").AppendRelativePath(path, &absolute_path));
  297. base::File::Info info;
  298. {
  299. base::ScopedAllowBlockingForTesting allow_io;
  300. if (!base::GetFileInfo(absolute_path, &info)) {
  301. std::move(callback).Run(drive::FILE_ERROR_NOT_FOUND, nullptr);
  302. return;
  303. }
  304. }
  305. auto metadata = drivefs::mojom::FileMetadata::New();
  306. metadata->size = info.size;
  307. metadata->modification_time = info.last_modified;
  308. metadata->last_viewed_by_me_time = info.last_accessed;
  309. if (metadata_[path].stable_id == 0) {
  310. metadata_[path].stable_id = next_stable_id_++;
  311. }
  312. const auto& stored_metadata = metadata_[path];
  313. metadata->pinned = stored_metadata.pinned;
  314. metadata->available_offline = stored_metadata.pinned;
  315. metadata->shared = stored_metadata.shared;
  316. metadata->content_mime_type = stored_metadata.mime_type;
  317. metadata->type = stored_metadata.hosted
  318. ? mojom::FileMetadata::Type::kHosted
  319. : info.is_directory
  320. ? mojom::FileMetadata::Type::kDirectory
  321. : mojom::FileMetadata::Type::kFile;
  322. if (!stored_metadata.alternate_url.empty()) {
  323. metadata->alternate_url = stored_metadata.alternate_url;
  324. } else {
  325. base::StringPiece prefix;
  326. if (stored_metadata.hosted) {
  327. prefix = "https://document_alternate_link/";
  328. } else if (info.is_directory) {
  329. prefix = "https://folder_alternate_link/";
  330. } else {
  331. prefix = "https://file_alternate_link/";
  332. }
  333. std::string suffix = stored_metadata.original_name.empty()
  334. ? path.BaseName().value()
  335. : stored_metadata.original_name;
  336. metadata->alternate_url = GURL(base::StrCat({prefix, suffix})).spec();
  337. }
  338. metadata->capabilities = stored_metadata.capabilities.Clone();
  339. metadata->stable_id = stored_metadata.stable_id;
  340. if (stored_metadata.hosted) {
  341. metadata->can_pin = mojom::FileMetadata::CanPinStatus::kDisabled;
  342. }
  343. std::move(callback).Run(drive::FILE_ERROR_OK, std::move(metadata));
  344. }
  345. void FakeDriveFs::SetPinned(const base::FilePath& path,
  346. bool pinned,
  347. SetPinnedCallback callback) {
  348. metadata_[path].pinned = pinned;
  349. std::move(callback).Run(drive::FILE_ERROR_OK);
  350. }
  351. void FakeDriveFs::UpdateNetworkState(bool pause_syncing, bool is_offline) {}
  352. void FakeDriveFs::ResetCache(ResetCacheCallback callback) {
  353. std::move(callback).Run(drive::FILE_ERROR_OK);
  354. }
  355. void FakeDriveFs::GetThumbnail(const base::FilePath& path,
  356. bool crop_to_square,
  357. GetThumbnailCallback callback) {
  358. std::move(callback).Run(absl::nullopt);
  359. }
  360. void FakeDriveFs::CopyFile(const base::FilePath& source,
  361. const base::FilePath& target,
  362. CopyFileCallback callback) {
  363. base::ScopedAllowBlockingForTesting allow_io;
  364. base::FilePath source_absolute_path = mount_path_;
  365. base::FilePath target_absolute_path = mount_path_;
  366. CHECK(base::FilePath("/").AppendRelativePath(source, &source_absolute_path));
  367. CHECK(base::FilePath("/").AppendRelativePath(target, &target_absolute_path));
  368. base::File::Info source_info;
  369. if (!base::GetFileInfo(source_absolute_path, &source_info)) {
  370. std::move(callback).Run(drive::FILE_ERROR_NOT_FOUND);
  371. return;
  372. }
  373. if (source_info.is_directory) {
  374. std::move(callback).Run(drive::FILE_ERROR_NOT_A_FILE);
  375. return;
  376. }
  377. base::File::Info target_directory_info;
  378. if (!base::GetFileInfo(target_absolute_path.DirName(),
  379. &target_directory_info)) {
  380. std::move(callback).Run(drive::FILE_ERROR_NOT_FOUND);
  381. return;
  382. }
  383. if (!target_directory_info.is_directory) {
  384. std::move(callback).Run(drive::FILE_ERROR_INVALID_OPERATION);
  385. return;
  386. }
  387. if (base::PathExists(target_absolute_path)) {
  388. std::move(callback).Run(drive::FILE_ERROR_INVALID_OPERATION);
  389. return;
  390. }
  391. if (!base::CopyFile(source_absolute_path, target_absolute_path)) {
  392. std::move(callback).Run(drive::FILE_ERROR_FAILED);
  393. return;
  394. }
  395. metadata_[target_absolute_path] = metadata_[source_absolute_path];
  396. metadata_[target_absolute_path].stable_id = next_stable_id_++;
  397. std::move(callback).Run(drive::FILE_ERROR_OK);
  398. }
  399. void FakeDriveFs::StartSearchQuery(
  400. mojo::PendingReceiver<drivefs::mojom::SearchQuery> receiver,
  401. drivefs::mojom::QueryParametersPtr query_params) {
  402. auto search_query = std::make_unique<SearchQuery>(weak_factory_.GetWeakPtr(),
  403. std::move(query_params));
  404. mojo::MakeSelfOwnedReceiver(std::move(search_query), std::move(receiver));
  405. }
  406. void FakeDriveFs::FetchAllChangeLogs() {}
  407. void FakeDriveFs::FetchChangeLog(
  408. std::vector<mojom::FetchChangeLogOptionsPtr> options) {}
  409. void FakeDriveFs::SendNativeMessageRequest(
  410. const std::string& request,
  411. SendNativeMessageRequestCallback callback) {
  412. std::move(callback).Run(drive::FILE_ERROR_SERVICE_UNAVAILABLE, "");
  413. }
  414. void FakeDriveFs::SetStartupArguments(const std::string& arguments,
  415. SetStartupArgumentsCallback callback) {
  416. std::move(callback).Run(false);
  417. }
  418. void FakeDriveFs::GetStartupArguments(GetStartupArgumentsCallback callback) {
  419. std::move(callback).Run("");
  420. }
  421. void FakeDriveFs::SetTracingEnabled(bool enabled) {}
  422. void FakeDriveFs::SetNetworkingEnabled(bool enabled) {}
  423. void FakeDriveFs::ForcePauseSyncing(bool enable) {}
  424. void FakeDriveFs::DumpAccountSettings() {}
  425. void FakeDriveFs::LoadAccountSettings() {}
  426. void FakeDriveFs::CreateNativeHostSession(
  427. drivefs::mojom::ExtensionConnectionParamsPtr params,
  428. mojo::PendingReceiver<drivefs::mojom::NativeMessagingHost> session,
  429. mojo::PendingRemote<drivefs::mojom::NativeMessagingPort> port) {}
  430. void FakeDriveFs::LocateFilesByItemIds(
  431. const std::vector<std::string>& item_ids,
  432. drivefs::mojom::DriveFs::LocateFilesByItemIdsCallback callback) {
  433. base::flat_map<std::string, base::FilePath> results;
  434. {
  435. base::ScopedAllowBlockingForTesting allow_io;
  436. base::FileEnumerator enumerator(
  437. mount_path_, true,
  438. base::FileEnumerator::FILES | base::FileEnumerator::DIRECTORIES);
  439. base::FilePath path = enumerator.Next();
  440. while (!path.empty()) {
  441. base::FilePath relative_path;
  442. CHECK(mount_path_.AppendRelativePath(path, &relative_path));
  443. const auto& stored_metadata =
  444. metadata_[base::FilePath("/").Append(relative_path)];
  445. if (!stored_metadata.doc_id.empty() &&
  446. base::Contains(item_ids, stored_metadata.doc_id)) {
  447. results[stored_metadata.doc_id] = relative_path;
  448. }
  449. path = enumerator.Next();
  450. }
  451. }
  452. std::vector<drivefs::mojom::FilePathOrErrorPtr> response;
  453. for (const auto& id : item_ids) {
  454. auto it = results.find(id);
  455. if (it == results.end()) {
  456. response.push_back(drivefs::mojom::FilePathOrError::NewError(
  457. drive::FileError::FILE_ERROR_NOT_FOUND));
  458. } else {
  459. response.push_back(drivefs::mojom::FilePathOrError::NewPath(it->second));
  460. }
  461. }
  462. std::move(callback).Run(std::move(response));
  463. }
  464. void FakeDriveFs::GetQuotaUsage(
  465. drivefs::mojom::DriveFs::GetQuotaUsageCallback callback) {
  466. std::move(callback).Run(drive::FileError::FILE_ERROR_SERVICE_UNAVAILABLE,
  467. mojom::QuotaUsage::New());
  468. }
  469. void FakeDriveFs::GetPooledQuotaUsage(
  470. drivefs::mojom::DriveFs::GetPooledQuotaUsageCallback callback) {
  471. auto usage = mojom::PooledQuotaUsage::New();
  472. usage->user_type = mojom::UserType::kUnmanaged;
  473. usage->used_user_bytes = 1 * 1024 * 1024;
  474. usage->total_user_bytes = 2 * 1024 * 1024;
  475. usage->organization_limit_exceeded = false;
  476. usage->organization_name = "Test Organization";
  477. std::move(callback).Run(drive::FileError::FILE_ERROR_OK, std::move(usage));
  478. }
  479. void FakeDriveFs::ToggleMirroring(
  480. bool enabled,
  481. drivefs::mojom::DriveFs::ToggleMirroringCallback callback) {
  482. std::move(callback).Run(drivefs::mojom::MirrorSyncStatus::kSuccess);
  483. }
  484. void FakeDriveFs::ToggleSyncForPath(
  485. const base::FilePath& path,
  486. drivefs::mojom::MirrorPathStatus status,
  487. drivefs::mojom::DriveFs::ToggleSyncForPathCallback callback) {
  488. if (status == drivefs::mojom::MirrorPathStatus::kStart) {
  489. syncing_paths_.push_back(path);
  490. } else {
  491. // status == drivefs::mojom::MirrorPathStatus::kStop.
  492. auto element =
  493. std::find(syncing_paths_.begin(), syncing_paths_.end(), path);
  494. syncing_paths_.erase(element);
  495. }
  496. std::move(callback).Run(drive::FileError::FILE_ERROR_OK);
  497. }
  498. void FakeDriveFs::PollHostedFilePinStates() {}
  499. } // namespace drivefs