disk_mount_manager.cc 41 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125
  1. // Copyright (c) 2012 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/disks/disk_mount_manager.h"
  5. #include <stddef.h>
  6. #include <stdint.h>
  7. #include <map>
  8. #include <memory>
  9. #include <set>
  10. #include <string>
  11. #include <type_traits>
  12. #include <utility>
  13. #include <vector>
  14. #include "ash/components/disks/disk.h"
  15. #include "ash/components/disks/suspend_unmount_manager.h"
  16. #include "base/barrier_closure.h"
  17. #include "base/bind.h"
  18. #include "base/callback_helpers.h"
  19. #include "base/logging.h"
  20. #include "base/memory/weak_ptr.h"
  21. #include "base/metrics/histogram_functions.h"
  22. #include "base/observer_list.h"
  23. #include "base/strings/string_util.h"
  24. #include "chromeos/ash/components/dbus/cros_disks/cros_disks_client.h"
  25. namespace ash::disks {
  26. namespace {
  27. using base::BindOnce;
  28. DiskMountManager* g_disk_mount_manager = nullptr;
  29. struct UnmountDeviceRecursivelyCallbackData {
  30. explicit UnmountDeviceRecursivelyCallbackData(
  31. DiskMountManager::UnmountDeviceRecursivelyCallbackType in_callback)
  32. : callback(std::move(in_callback)) {}
  33. DiskMountManager::UnmountDeviceRecursivelyCallbackType callback;
  34. MountError error_code = MountError::kNone;
  35. };
  36. void OnAllUnmountDeviceRecursively(
  37. std::unique_ptr<UnmountDeviceRecursivelyCallbackData> cb_data) {
  38. std::move(cb_data->callback).Run(cb_data->error_code);
  39. }
  40. std::string FormatFileSystemTypeToString(FormatFileSystemType filesystem) {
  41. switch (filesystem) {
  42. case FormatFileSystemType::kUnknown:
  43. return "";
  44. case FormatFileSystemType::kVfat:
  45. return "vfat";
  46. case FormatFileSystemType::kExfat:
  47. return "exfat";
  48. case FormatFileSystemType::kNtfs:
  49. return "ntfs";
  50. }
  51. NOTREACHED() << "Unknown filesystem type " << static_cast<int>(filesystem);
  52. return "";
  53. }
  54. // The DiskMountManager implementation.
  55. class DiskMountManagerImpl : public DiskMountManager,
  56. public CrosDisksClient::Observer {
  57. public:
  58. DiskMountManagerImpl() { cros_disks_client_->AddObserver(this); }
  59. DiskMountManagerImpl(const DiskMountManagerImpl&) = delete;
  60. DiskMountManagerImpl& operator=(const DiskMountManagerImpl&) = delete;
  61. ~DiskMountManagerImpl() override { cros_disks_client_->RemoveObserver(this); }
  62. // DiskMountManager override.
  63. void AddObserver(DiskMountManager::Observer* observer) override {
  64. observers_.AddObserver(observer);
  65. }
  66. // DiskMountManager override.
  67. void RemoveObserver(DiskMountManager::Observer* observer) override {
  68. observers_.RemoveObserver(observer);
  69. }
  70. // DiskMountManager override.
  71. void MountPath(const std::string& source_path,
  72. const std::string& source_format,
  73. const std::string& mount_label,
  74. const std::vector<std::string>& mount_options,
  75. MountType type,
  76. MountAccessMode access_mode,
  77. MountPathCallback callback) override {
  78. if (const auto [_, ok] =
  79. mount_callbacks_.try_emplace(source_path, std::move(callback));
  80. !ok) {
  81. std::move(callback).Run(MountError::kPathAlreadyMounted,
  82. {source_path, "", type});
  83. return;
  84. }
  85. // Hidden and non-existent devices should not be mounted.
  86. if (type == MountType::kDevice) {
  87. Disks::const_iterator it = disks_.find(source_path);
  88. if (it == disks_.end() || it->get()->is_hidden()) {
  89. OnMountCompleted({MountError::kInternal, source_path, type});
  90. return;
  91. }
  92. }
  93. cros_disks_client_->Mount(
  94. source_path, source_format, mount_label, mount_options, access_mode,
  95. RemountOption::kMountNewDevice,
  96. BindOnce(&DiskMountManagerImpl::OnMount, weak_ptr_factory_.GetWeakPtr(),
  97. source_path, type));
  98. // Record the access mode option passed to CrosDisks.
  99. // This is needed because CrosDisks service methods doesn't return the info
  100. // via DBus.
  101. access_modes_.emplace(source_path, access_mode);
  102. }
  103. // DiskMountManager override.
  104. void UnmountPath(const std::string& mount_path,
  105. UnmountPathCallback callback) override {
  106. UnmountChildMounts(mount_path);
  107. cros_disks_client_->Unmount(mount_path,
  108. BindOnce(&DiskMountManagerImpl::OnUnmountPath,
  109. weak_ptr_factory_.GetWeakPtr(),
  110. std::move(callback), mount_path));
  111. }
  112. void RemountAllRemovableDrives(MountAccessMode mode) override {
  113. // TODO(yamaguchi): Retry for tentative remount failures. crbug.com/661455
  114. for (const auto& disk : disks_) {
  115. DCHECK(disk);
  116. if (disk->is_read_only_hardware()) {
  117. // Read-only devices can be mounted in RO mode only. No need to remount.
  118. continue;
  119. }
  120. if (!disk->is_mounted()) {
  121. continue;
  122. }
  123. RemountRemovableDrive(*disk, mode);
  124. }
  125. }
  126. // DiskMountManager override.
  127. void FormatMountedDevice(const std::string& mount_path,
  128. FormatFileSystemType filesystem,
  129. const std::string& label) override {
  130. MountPoints::const_iterator mount_point = mount_points_.find(mount_path);
  131. if (mount_point == mount_points_.end()) {
  132. LOG(ERROR) << "Cannot find mount point '" << mount_path << "'";
  133. // We can't call OnFormatCompleted until |pending_format_changes_| has
  134. // been populated.
  135. NotifyFormatStatusUpdate(FORMAT_COMPLETED, FormatError::kUnknown,
  136. mount_path, label);
  137. return;
  138. }
  139. std::string device_path = mount_point->source_path;
  140. const std::string filesystem_str = FormatFileSystemTypeToString(filesystem);
  141. pending_format_changes_[device_path] = {filesystem_str, label};
  142. Disks::const_iterator disk = disks_.find(device_path);
  143. if (disk == disks_.end()) {
  144. LOG(ERROR) << "Cannot find device '" << device_path << "'";
  145. OnFormatCompleted(FormatError::kUnknown, device_path);
  146. return;
  147. }
  148. if (disk->get()->is_read_only()) {
  149. LOG(ERROR) << "Device '" << device_path << "' is read-only";
  150. OnFormatCompleted(FormatError::kDeviceNotAllowed, device_path);
  151. return;
  152. }
  153. if (filesystem == FormatFileSystemType::kUnknown) {
  154. LOG(ERROR) << "Unknown filesystem passed to FormatMountedDevice";
  155. OnFormatCompleted(FormatError::kUnsupportedFilesystem, device_path);
  156. return;
  157. }
  158. UnmountPath(disk->get()->mount_path(),
  159. BindOnce(&DiskMountManagerImpl::OnUnmountPathForFormat,
  160. weak_ptr_factory_.GetWeakPtr(), device_path,
  161. filesystem, label));
  162. }
  163. // DiskMountManager override.
  164. void SinglePartitionFormatDevice(const std::string& device_path,
  165. FormatFileSystemType filesystem,
  166. const std::string& label) override {
  167. Disks::const_iterator disk_iter = disks_.find(device_path);
  168. if (disk_iter == disks_.end()) {
  169. LOG(ERROR) << "Cannot find device '" << device_path << "'";
  170. OnPartitionCompleted(device_path, filesystem, label,
  171. PartitionError::kInvalidDevicePath);
  172. return;
  173. }
  174. UnmountDeviceRecursively(
  175. device_path,
  176. BindOnce(&DiskMountManagerImpl::OnUnmountDeviceForSinglePartitionFormat,
  177. weak_ptr_factory_.GetWeakPtr(), device_path, filesystem,
  178. label));
  179. }
  180. void RenameMountedDevice(const std::string& mount_path,
  181. const std::string& volume_name) override {
  182. MountPoints::const_iterator mount_point = mount_points_.find(mount_path);
  183. if (mount_point == mount_points_.end()) {
  184. LOG(ERROR) << "Cannot find mount point '" << mount_path << "'";
  185. // We can't call OnRenameCompleted until |pending_rename_changes_| has
  186. // been populated.
  187. NotifyRenameStatusUpdate(RENAME_COMPLETED, RenameError::kUnknown,
  188. mount_path, volume_name);
  189. return;
  190. }
  191. std::string device_path = mount_point->source_path;
  192. pending_rename_changes_[device_path] = volume_name;
  193. Disks::const_iterator iter = disks_.find(device_path);
  194. if (iter == disks_.end()) {
  195. LOG(ERROR) << "Cannot find device '" << device_path << "'";
  196. OnRenameCompleted(RenameError::kUnknown, device_path);
  197. return;
  198. }
  199. if (iter->get()->is_read_only()) {
  200. LOG(ERROR) << "Device '" << device_path << "' is read-only";
  201. OnRenameCompleted(RenameError::kDeviceNotAllowed, device_path);
  202. return;
  203. }
  204. UnmountPath(
  205. iter->get()->mount_path(),
  206. BindOnce(&DiskMountManagerImpl::OnUnmountPathForRename,
  207. weak_ptr_factory_.GetWeakPtr(), device_path, volume_name));
  208. }
  209. // DiskMountManager override.
  210. void UnmountDeviceRecursively(
  211. const std::string& device_path,
  212. UnmountDeviceRecursivelyCallbackType callback) override {
  213. std::vector<std::string> devices_to_unmount;
  214. // Get list of all devices to unmount.
  215. int device_path_len = device_path.length();
  216. for (const auto& disk : disks_) {
  217. if (!disk->mount_path().empty() &&
  218. strncmp(device_path.c_str(), disk->device_path().c_str(),
  219. device_path_len) == 0) {
  220. devices_to_unmount.push_back(disk->mount_path());
  221. }
  222. }
  223. // We should detect at least original device.
  224. if (devices_to_unmount.empty()) {
  225. if (disks_.find(device_path) == disks_.end()) {
  226. LOG(WARNING) << "Cannot find device '" << device_path << "'";
  227. std::move(callback).Run(MountError::kInvalidDevicePath);
  228. return;
  229. }
  230. // Nothing to unmount.
  231. std::move(callback).Run(MountError::kNone);
  232. return;
  233. }
  234. std::unique_ptr<UnmountDeviceRecursivelyCallbackData> cb_data =
  235. std::make_unique<UnmountDeviceRecursivelyCallbackData>(
  236. std::move(callback));
  237. UnmountDeviceRecursivelyCallbackData* raw_cb_data = cb_data.get();
  238. base::RepeatingClosure done_callback = base::BarrierClosure(
  239. devices_to_unmount.size(),
  240. BindOnce(&OnAllUnmountDeviceRecursively, std::move(cb_data)));
  241. for (const std::string& device : devices_to_unmount) {
  242. cros_disks_client_->Unmount(
  243. device, BindOnce(&DiskMountManagerImpl::OnUnmountDeviceRecursively,
  244. weak_ptr_factory_.GetWeakPtr(), raw_cb_data, device,
  245. done_callback));
  246. }
  247. }
  248. // DiskMountManager override.
  249. void EnsureMountInfoRefreshed(EnsureMountInfoRefreshedCallback callback,
  250. bool force) override {
  251. if (!force && already_refreshed_) {
  252. std::move(callback).Run(true);
  253. return;
  254. }
  255. refresh_callbacks_.push_back(std::move(callback));
  256. if (refresh_callbacks_.size() == 1) {
  257. // If there's no in-flight refreshing task, start it.
  258. cros_disks_client_->EnumerateDevices(
  259. BindOnce(&DiskMountManagerImpl::RefreshAfterEnumerateDevices,
  260. weak_ptr_factory_.GetWeakPtr()),
  261. BindOnce(&DiskMountManagerImpl::RefreshCompleted,
  262. weak_ptr_factory_.GetWeakPtr(), false));
  263. }
  264. }
  265. // DiskMountManager override.
  266. const Disks& disks() const override { return disks_; }
  267. // DiskMountManager override.
  268. const Disk* FindDiskBySourcePath(
  269. const std::string& source_path) const override {
  270. Disks::const_iterator disk_it = disks_.find(source_path);
  271. return disk_it == disks_.end() ? nullptr : disk_it->get();
  272. }
  273. // DiskMountManager override.
  274. const MountPoints& mount_points() const override { return mount_points_; }
  275. // DiskMountManager override.
  276. bool AddDiskForTest(std::unique_ptr<Disk> disk) override {
  277. if (disks_.find(disk->device_path()) != disks_.end()) {
  278. LOG(ERROR) << "Attempt to add a duplicate disk";
  279. return false;
  280. }
  281. disks_.insert(std::move(disk));
  282. return true;
  283. }
  284. // DiskMountManager override.
  285. // Corresponding disk should be added to the manager before this is called.
  286. bool AddMountPointForTest(const MountPoint& mount_point) override {
  287. if (mount_points_.find(mount_point.mount_path) != mount_points_.end()) {
  288. LOG(ERROR) << "Attempt to add a duplicate mount point";
  289. return false;
  290. }
  291. if (mount_point.mount_type == MountType::kDevice &&
  292. disks_.find(mount_point.source_path) == disks_.end()) {
  293. LOG(ERROR) << "Device mount points must have a disk entry";
  294. return false;
  295. }
  296. mount_points_.insert(mount_point);
  297. return true;
  298. }
  299. private:
  300. // A struct to represent information about a format changes.
  301. struct FormatChange {
  302. // new file system type
  303. std::string file_system_type;
  304. // New volume name
  305. std::string volume_name;
  306. };
  307. // Stores new volume name and file system type for a device on which
  308. // formatting is invoked on, so that OnFormatCompleted can set it back to
  309. // |disks_|. The key is a device_path and the value is a FormatChange.
  310. std::map<std::string, FormatChange> pending_format_changes_;
  311. // Stores device path are being partitioning.
  312. // It allows preventing auto-mount of the disks in this set.
  313. std::set<std::string> pending_partitioning_disks_;
  314. // Stores new volume name for a device on which renaming is invoked on, so
  315. // that OnRenameCompleted can set it back to |disks_|. The key is a
  316. // device_path and the value is new volume_name.
  317. std::map<std::string, std::string> pending_rename_changes_;
  318. // Called on D-Bus CrosDisksClient::Mount() is done.
  319. void OnMount(const std::string& source_path, MountType type, bool result) {
  320. // When succeeds, OnMountCompleted will be called by "MountCompleted",
  321. // signal instead. Do nothing now.
  322. if (result)
  323. return;
  324. OnMountCompleted({MountError::kInternal, source_path, type});
  325. }
  326. void RemountRemovableDrive(const Disk& disk, MountAccessMode access_mode) {
  327. const std::string& mount_path = disk.mount_path();
  328. MountPoints::const_iterator mount_point = mount_points_.find(mount_path);
  329. if (mount_point == mount_points_.end()) {
  330. // Not in mount_points_. This happens when the mount_points and disks_ are
  331. // inconsistent.
  332. LOG(ERROR) << "Cannot find mount point '" << mount_path << "'";
  333. OnMountCompleted({MountError::kPathNotMounted, disk.device_path(),
  334. MountType::kDevice, mount_path});
  335. return;
  336. }
  337. const std::string& source_path = mount_point->source_path;
  338. // Update the access mode option passed to CrosDisks.
  339. // This is needed because CrosDisks service methods doesn't return the info
  340. // via DBus, and must be updated before issuing Mount command as it'll be
  341. // read by the handler of MountCompleted signal.
  342. access_modes_[source_path] = access_mode;
  343. cros_disks_client_->Mount(
  344. source_path, std::string(), std::string(), {}, access_mode,
  345. RemountOption::kRemountExistingDevice,
  346. BindOnce(&DiskMountManagerImpl::OnMount, weak_ptr_factory_.GetWeakPtr(),
  347. source_path, mount_point->mount_type));
  348. }
  349. // Unmounts all mount points whose source path is transitively parented by
  350. // |mount_path|.
  351. void UnmountChildMounts(std::string mount_path) {
  352. DCHECK(!mount_path.empty());
  353. // Let's make sure mount path has trailing slash.
  354. if (mount_path.back() != '/')
  355. mount_path += '/';
  356. for (const auto& mount_point : mount_points_) {
  357. if (base::StartsWith(mount_point.source_path, mount_path,
  358. base::CompareCase::SENSITIVE)) {
  359. UnmountPath(mount_point.mount_path,
  360. BindOnce(
  361. [](const std::string& path, MountError error) {
  362. LOG(ERROR)
  363. << "Cannot unmount '" << path << "': " << error;
  364. },
  365. mount_point.mount_path));
  366. }
  367. }
  368. }
  369. // Callback for UnmountDeviceRecursively.
  370. void OnUnmountDeviceRecursively(UnmountDeviceRecursivelyCallbackData* cb_data,
  371. const std::string& mount_path,
  372. base::OnceClosure done_callback,
  373. MountError error_code) {
  374. if (error_code == MountError::kPathNotMounted ||
  375. error_code == MountError::kInvalidPath) {
  376. // The path was already unmounted by something else.
  377. error_code = MountError::kNone;
  378. }
  379. if (error_code == MountError::kNone) {
  380. // Do standard processing for Unmount event.
  381. OnUnmountPath(UnmountPathCallback(), mount_path, MountError::kNone);
  382. VLOG(1) << "Unmounted '" << mount_path << "'";
  383. } else {
  384. // This causes the last non-success error to be reported.
  385. cb_data->error_code = error_code;
  386. }
  387. std::move(done_callback).Run();
  388. }
  389. // CrosDisksClient::Observer override.
  390. void OnMountCompleted(const MountEntry& entry) override {
  391. auto iter = deferred_mount_events_.find(entry.source_path);
  392. if (iter != deferred_mount_events_.end()) {
  393. iter->second.push_back(entry);
  394. return;
  395. }
  396. MountCondition mount_condition = MountCondition::kNone;
  397. if (entry.mount_type == MountType::kDevice) {
  398. if (entry.error_code == MountError::kUnknownFilesystem) {
  399. mount_condition = MountCondition::kUnknownFilesystem;
  400. }
  401. if (entry.error_code == MountError::kUnsupportedFilesystem) {
  402. mount_condition = MountCondition::kUnsupportedFilesystem;
  403. }
  404. }
  405. const MountPoint mount_info{entry.source_path, entry.mount_path,
  406. entry.mount_type, mount_condition};
  407. // If the device is corrupted but it's still possible to format it, it will
  408. // be fake mounted.
  409. if (entry.error_code == MountError::kNone ||
  410. mount_condition != MountCondition::kNone) {
  411. mount_points_.insert(mount_info);
  412. }
  413. Disk* disk = nullptr;
  414. if ((entry.error_code == MountError::kNone ||
  415. mount_info.mount_condition != MountCondition::kNone) &&
  416. mount_info.mount_type == MountType::kDevice &&
  417. !mount_info.source_path.empty() && !mount_info.mount_path.empty()) {
  418. Disks::iterator disk_map_iter = disks_.find(mount_info.source_path);
  419. if (disk_map_iter != disks_.end()) { // disk might have been removed?
  420. disk = disk_map_iter->get();
  421. DCHECK(disk);
  422. // Currently the MountCompleted signal doesn't tell whether the device
  423. // is mounted in read-only mode or not. Instead use the mount option
  424. // recorded by DiskMountManagerImpl::MountPath().
  425. // |source_path| should be same as |disk->device_path| because
  426. // |VolumeManager::OnDiskEvent()| passes the latter to cros-disks as a
  427. // source path when mounting a device.
  428. AccessModeMap::iterator it = access_modes_.find(entry.source_path);
  429. // Store whether the disk was mounted in read-only mode due to a policy.
  430. disk->set_write_disabled_by_policy(
  431. it != access_modes_.end() && !disk->is_read_only_hardware() &&
  432. it->second == MountAccessMode::kReadOnly);
  433. disk->SetMountPath(mount_info.mount_path);
  434. // Only set the mount path if the disk is actually mounted. Right now, a
  435. // number of code paths (format, rename, unmount) rely on the mount path
  436. // being set even if the disk isn't mounted. cros-disks also does some
  437. // tracking of non-mounted mount paths. Making this change is
  438. // non-trivial.
  439. // TODO(amistry): Change these code paths to use device path instead of
  440. // mount path.
  441. disk->set_mounted(entry.error_code == MountError::kNone);
  442. }
  443. }
  444. // Observers may read the values of disks_. So notify them after tweaking
  445. // values of disks_.
  446. auto it = mount_callbacks_.find(entry.source_path);
  447. if (it != mount_callbacks_.end()) {
  448. std::move(it->second).Run(entry.error_code, mount_info);
  449. mount_callbacks_.erase(it);
  450. }
  451. NotifyMountStatusUpdate(MOUNTING, entry.error_code, mount_info);
  452. if (disk) {
  453. disk->set_is_first_mount(false);
  454. }
  455. }
  456. // CrosDisksClient::Observer override.
  457. void OnMountProgress(const MountEntry& entry) override {
  458. VLOG(1) << "OnMountProgress: " << entry;
  459. }
  460. // Callback for UnmountPath.
  461. void OnUnmountPath(UnmountPathCallback callback,
  462. const std::string& mount_path,
  463. MountError error) {
  464. if (error == MountError::kPathNotMounted ||
  465. error == MountError::kInvalidPath) {
  466. // The path was already unmounted by something else.
  467. error = MountError::kNone;
  468. }
  469. if (const MountPoints::const_iterator mp_it =
  470. mount_points_.find(mount_path);
  471. mp_it != mount_points_.end()) {
  472. const MountPoint& mp = *mp_it;
  473. NotifyMountStatusUpdate(UNMOUNTING, error, mp);
  474. if (error == MountError::kNone) {
  475. if (const Disks::iterator disk_it = disks_.find(mp.source_path);
  476. disk_it != disks_.end()) {
  477. Disk* const disk = disk_it->get();
  478. DCHECK(disk);
  479. disk->clear_mount_path();
  480. disk->set_mounted(false);
  481. }
  482. mount_points_.erase(mp_it);
  483. }
  484. }
  485. if (callback)
  486. std::move(callback).Run(error);
  487. }
  488. void OnUnmountPathForFormat(const std::string& device_path,
  489. FormatFileSystemType filesystem,
  490. const std::string& label,
  491. MountError error_code) {
  492. if (error_code == MountError::kNone && disks_.count(device_path) != 0) {
  493. FormatUnmountedDevice(device_path, filesystem, label);
  494. } else {
  495. OnFormatCompleted(FormatError::kUnknown, device_path);
  496. }
  497. }
  498. void OnUnmountDeviceForSinglePartitionFormat(const std::string& device_path,
  499. FormatFileSystemType filesystem,
  500. const std::string& label,
  501. MountError error_code) {
  502. if (error_code != MountError::kNone || disks_.count(device_path) == 0) {
  503. OnPartitionCompleted(device_path, filesystem, label,
  504. PartitionError::kUnknown);
  505. return;
  506. }
  507. SinglePartitionFormatUnmountedDevice(device_path, filesystem, label);
  508. }
  509. // Starts device formatting.
  510. void FormatUnmountedDevice(const std::string& device_path,
  511. FormatFileSystemType filesystem,
  512. const std::string& label) {
  513. Disks::const_iterator disk = disks_.find(device_path);
  514. DCHECK(disk != disks_.end() && disk->get()->mount_path().empty());
  515. base::UmaHistogramEnumeration("FileBrowser.FormatFileSystemType",
  516. filesystem);
  517. cros_disks_client_->Format(
  518. device_path, FormatFileSystemTypeToString(filesystem), label,
  519. BindOnce(&DiskMountManagerImpl::OnFormatStarted,
  520. weak_ptr_factory_.GetWeakPtr(), device_path, label));
  521. }
  522. // Callback for Format.
  523. void OnFormatStarted(const std::string& device_path,
  524. const std::string& device_label,
  525. bool success) {
  526. if (!success) {
  527. OnFormatCompleted(FormatError::kUnknown, device_path);
  528. return;
  529. }
  530. NotifyFormatStatusUpdate(FORMAT_STARTED, FormatError::kNone, device_path,
  531. device_label);
  532. }
  533. // CrosDisksClient::Observer override.
  534. void OnFormatCompleted(FormatError error_code,
  535. const std::string& device_path) override {
  536. std::string device_label;
  537. auto pending_change = pending_format_changes_.find(device_path);
  538. if (pending_change != pending_format_changes_.end()) {
  539. device_label = pending_change->second.volume_name;
  540. }
  541. auto iter = disks_.find(device_path);
  542. // disk might have been removed by now?
  543. if (iter != disks_.end()) {
  544. Disk* const disk = iter->get();
  545. DCHECK(disk);
  546. if (pending_change != pending_format_changes_.end() &&
  547. error_code == FormatError::kNone) {
  548. disk->set_device_label(pending_change->second.volume_name);
  549. disk->set_file_system_type(pending_change->second.file_system_type);
  550. }
  551. }
  552. pending_format_changes_.erase(device_path);
  553. EnsureMountInfoRefreshed(base::DoNothing(), true /* force */);
  554. NotifyFormatStatusUpdate(FORMAT_COMPLETED, error_code, device_path,
  555. device_label);
  556. }
  557. void SinglePartitionFormatUnmountedDevice(const std::string& device_path,
  558. FormatFileSystemType filesystem,
  559. const std::string& label) {
  560. Disks::const_iterator disk = disks_.find(device_path);
  561. DCHECK(disk != disks_.end() && disk->get()->mount_path().empty());
  562. pending_partitioning_disks_.insert(disk->get()->device_path());
  563. NotifyPartitionStatusUpdate(PARTITION_STARTED, PartitionError::kNone,
  564. device_path, label);
  565. cros_disks_client_->SinglePartitionFormat(
  566. disk->get()->file_path(),
  567. BindOnce(&DiskMountManagerImpl::OnPartitionCompleted,
  568. weak_ptr_factory_.GetWeakPtr(), device_path, filesystem,
  569. label));
  570. }
  571. void OnPartitionCompleted(const std::string& device_path,
  572. FormatFileSystemType filesystem,
  573. const std::string& label,
  574. PartitionError error_code) {
  575. auto iter = disks_.find(device_path);
  576. // disk might have been removed by now?
  577. if (iter != disks_.end()) {
  578. Disk* const disk = iter->get();
  579. DCHECK(disk);
  580. if (error_code == PartitionError::kNone) {
  581. EnsureMountInfoRefreshed(
  582. BindOnce(&DiskMountManagerImpl::OnRefreshAfterPartition,
  583. weak_ptr_factory_.GetWeakPtr(), device_path, filesystem,
  584. label),
  585. true /* force */);
  586. }
  587. } else {
  588. // Remove disk from pending partitioning list if disk removed.
  589. pending_partitioning_disks_.erase(device_path);
  590. }
  591. NotifyPartitionStatusUpdate(PARTITION_COMPLETED, error_code, device_path,
  592. label);
  593. }
  594. void OnRefreshAfterPartition(const std::string& device_path,
  595. FormatFileSystemType filesystem,
  596. const std::string& label,
  597. bool success) {
  598. Disks::const_iterator device_disk = disks_.find(device_path);
  599. if (device_disk == disks_.end()) {
  600. LOG(ERROR) << "Device not found, maybe ejected";
  601. pending_partitioning_disks_.erase(device_path);
  602. NotifyPartitionStatusUpdate(PARTITION_COMPLETED,
  603. PartitionError::kInvalidDevicePath,
  604. device_path, label);
  605. return;
  606. }
  607. std::string new_partition_device_path;
  608. // Find new partition using common storage path with parent device.
  609. for (const auto& candidate : disks_) {
  610. if (candidate->storage_device_path() ==
  611. device_disk->get()->storage_device_path() &&
  612. !candidate->is_parent()) {
  613. new_partition_device_path = candidate->device_path();
  614. break;
  615. }
  616. }
  617. if (new_partition_device_path.empty()) {
  618. LOG(ERROR) << "New partition couldn't be found";
  619. pending_partitioning_disks_.erase(device_path);
  620. NotifyPartitionStatusUpdate(PARTITION_COMPLETED,
  621. PartitionError::kInvalidDevicePath,
  622. device_path, label);
  623. return;
  624. }
  625. const std::string filesystem_str = FormatFileSystemTypeToString(filesystem);
  626. pending_format_changes_[new_partition_device_path] = {filesystem_str,
  627. label};
  628. // It's expected the disks (parent device and new partition) are not
  629. // mounted, but try unmounting before starting format if it got
  630. // mounted through another flow.
  631. UnmountDeviceRecursively(
  632. device_path, BindOnce(&DiskMountManagerImpl::OnUnmountPathForFormat,
  633. weak_ptr_factory_.GetWeakPtr(),
  634. new_partition_device_path, filesystem, label));
  635. // It's ok to remove it from pending partitioning as format flow started.
  636. pending_partitioning_disks_.erase(device_path);
  637. }
  638. void OnUnmountPathForRename(const std::string& device_path,
  639. const std::string& volume_name,
  640. MountError error_code) {
  641. if (error_code != MountError::kNone || disks_.count(device_path) == 0) {
  642. OnRenameCompleted(RenameError::kUnknown, device_path);
  643. return;
  644. }
  645. RenameUnmountedDevice(device_path, volume_name);
  646. }
  647. // Start device renaming
  648. void RenameUnmountedDevice(const std::string& device_path,
  649. const std::string& volume_name) {
  650. const Disks::const_iterator disk = disks_.find(device_path);
  651. DCHECK(disk != disks_.end() && disk->get()->mount_path().empty());
  652. cros_disks_client_->Rename(
  653. device_path, volume_name,
  654. BindOnce(&DiskMountManagerImpl::OnRenameStarted,
  655. weak_ptr_factory_.GetWeakPtr(), device_path, volume_name));
  656. }
  657. // Callback for Rename.
  658. void OnRenameStarted(const std::string& device_path,
  659. const std::string& volume_name,
  660. bool success) {
  661. if (!success) {
  662. OnRenameCompleted(RenameError::kUnknown, device_path);
  663. return;
  664. }
  665. NotifyRenameStatusUpdate(RENAME_STARTED, RenameError::kNone, device_path,
  666. volume_name);
  667. }
  668. // CrosDisksClient::Observer override.
  669. void OnRenameCompleted(RenameError error_code,
  670. const std::string& device_path) override {
  671. std::string device_label;
  672. auto pending_change = pending_rename_changes_.find(device_path);
  673. if (pending_change != pending_rename_changes_.end()) {
  674. device_label = pending_change->second;
  675. }
  676. auto iter = disks_.find(device_path);
  677. // disk might have been removed by now?
  678. if (iter != disks_.end()) {
  679. Disk* const disk = iter->get();
  680. DCHECK(disk);
  681. if (pending_change != pending_rename_changes_.end() &&
  682. error_code == RenameError::kNone)
  683. disk->set_device_label(pending_change->second);
  684. }
  685. pending_rename_changes_.erase(device_path);
  686. NotifyRenameStatusUpdate(RENAME_COMPLETED, error_code, device_path,
  687. device_label);
  688. }
  689. // Fire observer mount events that were deferred due to an in-progress
  690. // GetDeviceProperties() call.
  691. void RunDeferredMountEvents(const std::string& device_path) {
  692. auto mount_events_iter = deferred_mount_events_.find(device_path);
  693. if (mount_events_iter == deferred_mount_events_.end())
  694. return;
  695. std::vector<MountEntry> entries = std::move(mount_events_iter->second);
  696. deferred_mount_events_.erase(mount_events_iter);
  697. for (const MountEntry& entry : entries)
  698. OnMountCompleted(entry);
  699. }
  700. // Callback for GetDeviceProperties.
  701. void OnGetDeviceProperties(const DiskInfo& disk_info) {
  702. if (disk_info.is_virtual()) {
  703. RunDeferredMountEvents(disk_info.device_path());
  704. return;
  705. }
  706. DVLOG(1) << "Found disk " << disk_info.device_path();
  707. // Delete previous disk info for this path:
  708. bool is_new = true;
  709. bool is_first_mount = false;
  710. std::string base_mount_path = std::string();
  711. Disks::iterator iter = disks_.find(disk_info.device_path());
  712. if (iter != disks_.end()) {
  713. is_first_mount = iter->get()->is_first_mount();
  714. base_mount_path = iter->get()->base_mount_path();
  715. disks_.erase(iter);
  716. is_new = false;
  717. }
  718. // If the device was mounted by the instance, apply recorded parameter.
  719. // Otherwise, default to false.
  720. // Lookup by |device_path| which we pass to cros-disks when mounting a
  721. // device in |VolumeManager::OnDiskEvent()|.
  722. auto access_mode = access_modes_.find(disk_info.device_path());
  723. bool write_disabled_by_policy =
  724. access_mode != access_modes_.end() &&
  725. access_mode->second == MountAccessMode::kReadOnly;
  726. std::unique_ptr<Disk> disk = std::make_unique<Disk>(
  727. disk_info, write_disabled_by_policy, base_mount_path);
  728. if (!is_new) {
  729. disk->set_is_first_mount(is_first_mount);
  730. }
  731. const auto [it, ok] = disks_.insert(std::move(disk));
  732. DCHECK(ok);
  733. NotifyDiskStatusUpdate(is_new ? DISK_ADDED : DISK_CHANGED, **it);
  734. RunDeferredMountEvents(disk_info.device_path());
  735. }
  736. // Part of EnsureMountInfoRefreshed(). Called after the list of devices are
  737. // enumerated.
  738. void RefreshAfterEnumerateDevices(const std::vector<std::string>& devices) {
  739. std::set<std::string> current_device_set(devices.begin(), devices.end());
  740. for (Disks::iterator iter = disks_.begin(); iter != disks_.end();) {
  741. if (current_device_set.count(iter->get()->device_path()) == 0) {
  742. iter = disks_.erase(iter);
  743. } else {
  744. ++iter;
  745. }
  746. }
  747. RefreshDeviceAtIndex(devices, 0);
  748. }
  749. // Part of EnsureMountInfoRefreshed(). Called for each device to refresh info.
  750. void RefreshDeviceAtIndex(const std::vector<std::string>& devices,
  751. size_t index) {
  752. if (index == devices.size()) {
  753. // All devices info retrieved. Proceed to enumerate mount point info.
  754. cros_disks_client_->EnumerateMountEntries(
  755. BindOnce(&DiskMountManagerImpl::RefreshAfterEnumerateMountEntries,
  756. weak_ptr_factory_.GetWeakPtr()),
  757. BindOnce(&DiskMountManagerImpl::RefreshCompleted,
  758. weak_ptr_factory_.GetWeakPtr(), false));
  759. return;
  760. }
  761. cros_disks_client_->GetDeviceProperties(
  762. devices[index],
  763. BindOnce(&DiskMountManagerImpl::RefreshAfterGetDeviceProperties,
  764. weak_ptr_factory_.GetWeakPtr(), devices, index + 1),
  765. BindOnce(&DiskMountManagerImpl::RefreshDeviceAtIndex,
  766. weak_ptr_factory_.GetWeakPtr(), devices, index + 1));
  767. }
  768. // Part of EnsureMountInfoRefreshed().
  769. void RefreshAfterGetDeviceProperties(const std::vector<std::string>& devices,
  770. size_t next_index,
  771. const DiskInfo& disk_info) {
  772. OnGetDeviceProperties(disk_info);
  773. RefreshDeviceAtIndex(devices, next_index);
  774. }
  775. // Part of EnsureMountInfoRefreshed(). Called after mount entries are listed.
  776. void RefreshAfterEnumerateMountEntries(
  777. const std::vector<MountEntry>& entries) {
  778. for (const auto& entry : entries)
  779. OnMountCompleted(entry);
  780. RefreshCompleted(true);
  781. }
  782. // Part of EnsureMountInfoRefreshed(). Called when the refreshing is done.
  783. void RefreshCompleted(bool success) {
  784. already_refreshed_ = true;
  785. for (auto& callback : refresh_callbacks_)
  786. std::move(callback).Run(success);
  787. refresh_callbacks_.clear();
  788. }
  789. // CrosDisksClient::Observer override.
  790. void OnMountEvent(MountEventType event,
  791. const std::string& device_path_arg) override {
  792. // Take a copy of the argument so we can modify it below.
  793. std::string device_path = device_path_arg;
  794. switch (event) {
  795. case MountEventType::kDiskAdded: {
  796. // Ensure we have an entry indicating we're waiting for
  797. // GetDeviceProperties() to complete.
  798. deferred_mount_events_[device_path];
  799. cros_disks_client_->GetDeviceProperties(
  800. device_path,
  801. BindOnce(&DiskMountManagerImpl::OnGetDeviceProperties,
  802. weak_ptr_factory_.GetWeakPtr()),
  803. base::DoNothing());
  804. break;
  805. }
  806. case MountEventType::kDiskRemoved: {
  807. // Search and remove disks that are no longer present.
  808. DiskMountManager::Disks::iterator iter = disks_.find(device_path);
  809. if (iter != disks_.end()) {
  810. Disk* disk = iter->get();
  811. NotifyDiskStatusUpdate(DISK_REMOVED, *disk);
  812. disks_.erase(iter);
  813. }
  814. break;
  815. }
  816. case MountEventType::kDeviceAdded: {
  817. NotifyDeviceStatusUpdate(DEVICE_ADDED, device_path);
  818. break;
  819. }
  820. case MountEventType::kDeviceRemoved: {
  821. NotifyDeviceStatusUpdate(DEVICE_REMOVED, device_path);
  822. break;
  823. }
  824. case MountEventType::kDeviceScanned: {
  825. NotifyDeviceStatusUpdate(DEVICE_SCANNED, device_path);
  826. break;
  827. }
  828. default: {
  829. LOG(ERROR) << "Unknown event: " << static_cast<int>(event);
  830. }
  831. }
  832. }
  833. // Notifies all observers about disk status update.
  834. void NotifyDiskStatusUpdate(DiskEvent event, const Disk& disk) {
  835. for (auto& observer : observers_) {
  836. // Skip mounting of new partitioned disks while waiting for the format.
  837. if (IsPendingPartitioningDisk(disk.device_path())) {
  838. continue;
  839. }
  840. disk.is_auto_mountable() ? observer.OnAutoMountableDiskEvent(event, disk)
  841. : observer.OnBootDeviceDiskEvent(event, disk);
  842. }
  843. }
  844. // Notifies all observers about device status update.
  845. void NotifyDeviceStatusUpdate(DeviceEvent event,
  846. const std::string& device_path) {
  847. for (auto& observer : observers_)
  848. observer.OnDeviceEvent(event, device_path);
  849. }
  850. // Notifies all observers about mount completion.
  851. void NotifyMountStatusUpdate(MountEvent event,
  852. MountError error_code,
  853. const MountPoint& mount_info) {
  854. for (auto& observer : observers_)
  855. observer.OnMountEvent(event, error_code, mount_info);
  856. }
  857. void NotifyFormatStatusUpdate(FormatEvent event,
  858. FormatError error_code,
  859. const std::string& device_path,
  860. const std::string& device_label) {
  861. for (auto& observer : observers_)
  862. observer.OnFormatEvent(event, error_code, device_path, device_label);
  863. }
  864. void NotifyPartitionStatusUpdate(PartitionEvent event,
  865. PartitionError error_code,
  866. const std::string& device_path,
  867. const std::string& device_label) {
  868. for (auto& observer : observers_)
  869. observer.OnPartitionEvent(event, error_code, device_path, device_label);
  870. }
  871. void NotifyRenameStatusUpdate(RenameEvent event,
  872. RenameError error_code,
  873. const std::string& device_path,
  874. const std::string& device_label) {
  875. for (auto& observer : observers_)
  876. observer.OnRenameEvent(event, error_code, device_path, device_label);
  877. }
  878. bool IsPendingPartitioningDisk(const std::string& device_path) {
  879. if (pending_partitioning_disks_.find(device_path) !=
  880. pending_partitioning_disks_.end()) {
  881. return true;
  882. }
  883. // If device path doesn't match check whether if it's a child path.
  884. for (const auto& disk : pending_partitioning_disks_) {
  885. if (base::StartsWith(device_path, disk, base::CompareCase::SENSITIVE)) {
  886. return true;
  887. }
  888. }
  889. return false;
  890. }
  891. // Mount event change observers.
  892. base::ObserverList<DiskMountManager::Observer> observers_;
  893. CrosDisksClient* const cros_disks_client_ = CrosDisksClient::Get();
  894. // The list of disks found.
  895. DiskMountManager::Disks disks_;
  896. std::map<std::string, MountPathCallback> mount_callbacks_;
  897. DiskMountManager::MountPoints mount_points_;
  898. // A map entry with a key of the device path will be created upon calling
  899. // GetDeviceProperties(), for deferring mount events, and removed once it has
  900. // completed. This prevents a race resulting in mount events being fired with
  901. // the corresponding Disk entry unexpectedly missing.
  902. std::map<std::string, std::vector<MountEntry>> deferred_mount_events_;
  903. bool already_refreshed_ = false;
  904. std::vector<EnsureMountInfoRefreshedCallback> refresh_callbacks_;
  905. SuspendUnmountManager suspend_unmount_manager_{this};
  906. // Whether the instance attempted to mount a device in read-only mode for
  907. // each source path.
  908. typedef std::map<std::string, MountAccessMode> AccessModeMap;
  909. AccessModeMap access_modes_;
  910. base::WeakPtrFactory<DiskMountManagerImpl> weak_ptr_factory_{this};
  911. };
  912. } // namespace
  913. std::ostream& operator<<(std::ostream& out, MountCondition condition) {
  914. switch (condition) {
  915. #define PRINT(s) \
  916. case MountCondition::s: \
  917. return out << #s;
  918. PRINT(kNone)
  919. PRINT(kUnknownFilesystem)
  920. PRINT(kUnsupportedFilesystem)
  921. #undef PRINT
  922. }
  923. return out << static_cast<std::underlying_type_t<MountCondition>>(condition);
  924. }
  925. DiskMountManager::Observer::~Observer() {
  926. DCHECK(!IsInObserverList());
  927. }
  928. bool DiskMountManager::AddDiskForTest(std::unique_ptr<Disk> disk) {
  929. return false;
  930. }
  931. bool DiskMountManager::AddMountPointForTest(const MountPoint& mount_point) {
  932. return false;
  933. }
  934. // static
  935. void DiskMountManager::Initialize() {
  936. if (g_disk_mount_manager) {
  937. LOG(WARNING) << "DiskMountManager was already initialized";
  938. return;
  939. }
  940. g_disk_mount_manager = new DiskMountManagerImpl();
  941. VLOG(1) << "DiskMountManager initialized";
  942. }
  943. // static
  944. void DiskMountManager::InitializeForTesting(
  945. DiskMountManager* disk_mount_manager) {
  946. if (g_disk_mount_manager) {
  947. LOG(WARNING) << "DiskMountManager was already initialized";
  948. return;
  949. }
  950. g_disk_mount_manager = disk_mount_manager;
  951. VLOG(1) << "DiskMountManager initialized";
  952. }
  953. // static
  954. void DiskMountManager::Shutdown() {
  955. if (!g_disk_mount_manager) {
  956. LOG(WARNING) << "DiskMountManager::Shutdown() called with NULL manager";
  957. return;
  958. }
  959. delete g_disk_mount_manager;
  960. g_disk_mount_manager = nullptr;
  961. VLOG(1) << "DiskMountManager Shutdown completed";
  962. }
  963. // static
  964. DiskMountManager* DiskMountManager::GetInstance() {
  965. return g_disk_mount_manager;
  966. }
  967. } // namespace ash::disks