blob: da906f55f10e2e2a0782ed8908c93934dc122874 [file] [log] [blame]
Ben Chan1e5a0cb2012-03-22 00:41:52 -07001// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
Ryan Cairnsea6505f2011-04-10 19:54:53 -07002// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Ben Chan5ccd9fe2013-11-13 18:28:27 -08005#include "cros-disks/disk_manager.h"
Ben Chane31d2aa2011-06-15 13:52:59 -07006
Ben Chan35cd7ae2019-05-02 22:42:37 -07007#include <errno.h>
Anand K Mistry6b19a972018-09-11 11:14:59 +10008#include <inttypes.h>
Ryan Cairnsea6505f2011-04-10 19:54:53 -07009#include <libudev.h>
Ben Chane31d2aa2011-06-15 13:52:59 -070010#include <string.h>
Ben Chanf51ff002011-04-25 12:41:57 -070011#include <sys/mount.h>
Anand K Mistry6b19a972018-09-11 11:14:59 +100012#include <time.h>
Ryan Cairnsea6505f2011-04-10 19:54:53 -070013
Ben Chan5e3ca672014-08-25 15:53:58 -070014#include <memory>
Ben Chan5e64fd72016-09-23 15:20:34 -070015#include <utility>
Ben Chan5e3ca672014-08-25 15:53:58 -070016
Ben Chan86a9cee2014-07-14 12:17:12 -070017#include <base/bind.h>
Qijiang Fan713061e2021-03-08 15:45:12 +090018#include <base/check.h>
Ben Chanbdc39742011-05-11 17:51:26 -070019#include <base/logging.h>
Mike Frysinger38ae98d2012-04-11 12:03:44 -040020#include <base/stl_util.h>
Anand K Mistry2a0147b2019-03-21 18:54:03 +110021#include <base/strings/string_piece.h>
Ben Chan97e20d42014-02-05 18:38:07 -080022#include <base/strings/string_util.h>
23#include <base/strings/stringprintf.h>
Anand K Mistry6b19a972018-09-11 11:14:59 +100024#include <base/time/time.h>
Ben Chanbdc39742011-05-11 17:51:26 -070025
Sergei Datsenko16821892019-04-05 11:26:38 +110026#include "cros-disks/device_ejector.h"
27#include "cros-disks/disk_monitor.h"
Sergei Datsenko18464b92020-11-05 21:22:46 +110028#include "cros-disks/fuse_mounter.h"
Ben Chanbe2b4a72011-11-08 13:42:23 -080029#include "cros-disks/metrics.h"
Ben Chan5ccd9fe2013-11-13 18:28:27 -080030#include "cros-disks/mount_options.h"
Anand K Mistryc7eba322020-01-15 17:45:38 +110031#include "cros-disks/mount_point.h"
Ben Chan29be9152011-07-25 14:39:48 -070032#include "cros-disks/platform.h"
François Degros8b4e31e2019-07-29 11:39:19 +100033#include "cros-disks/quote.h"
Ben Chan5ccd9fe2013-11-13 18:28:27 -080034#include "cros-disks/system_mounter.h"
Ryan Cairnsea6505f2011-04-10 19:54:53 -070035
Ben Chan86a9cee2014-07-14 12:17:12 -070036namespace cros_disks {
37
Sergei Datsenko18464b92020-11-05 21:22:46 +110038namespace {
Sergei Datsenko68cd43a2020-11-16 22:57:16 +110039
Sergei Datsenko3928f782020-12-31 09:14:04 +110040constexpr char kOptionDirSync[] = "dirsync";
41constexpr char kOptionFlush[] = "flush";
42constexpr char kOptionUtf8[] = "utf8";
43
Sergei Datsenko68cd43a2020-11-16 22:57:16 +110044// Implementation of FUSEMounter aimed at removable storage with
45// exFAT or NTFS filesystems.
46class DiskFUSEMounter : public FUSEMounter {
47 public:
48 DiskFUSEMounter(const Platform* platform,
49 brillo::ProcessReaper* reaper,
50 std::string filesystem_type,
51 const SandboxedProcessFactory* upstream_factory,
52 SandboxedExecutable executable,
53 OwnerUser run_as,
54 std::vector<std::string> options)
Sergei Datsenko1d2cbf82020-12-08 21:54:42 +110055 : FUSEMounter(platform, reaper, std::move(filesystem_type), {}),
Sergei Datsenko68cd43a2020-11-16 22:57:16 +110056 upstream_factory_(upstream_factory),
57 sandbox_factory_(platform,
58 std::move(executable),
59 run_as,
60 false, // no network needed
61 {},
62 {}),
63 options_(std::move(options)) {}
64
65 private:
66 // FUSEMounter overrides:
67 bool CanMount(const std::string& source,
68 const std::vector<std::string>& params,
69 base::FilePath* suggested_name) const override {
70 if (suggested_name)
71 *suggested_name = base::FilePath("disk");
72 return true;
73 }
74
75 std::unique_ptr<SandboxedProcess> PrepareSandbox(
76 const std::string& source,
77 const base::FilePath&,
78 std::vector<std::string>,
79 MountErrorType* error) const override {
80 auto device = base::FilePath(source);
81
82 if (!device.IsAbsolute() || device.ReferencesParent() ||
83 !base::StartsWith(device.value(), "/dev/",
84 base::CompareCase::SENSITIVE)) {
85 LOG(ERROR) << "Source path " << quote(device) << " is invalid";
86 *error = MOUNT_ERROR_INVALID_ARGUMENT;
87 return nullptr;
88 }
89
90 if (!platform()->PathExists(device.value())) {
91 LOG(ERROR) << "Source path " << quote(device) << " does not exist";
92 *error = MOUNT_ERROR_INVALID_DEVICE_PATH;
93 return nullptr;
94 }
95
96 // Make sure the FUSE user can read-write to the device.
97 if (!platform()->SetOwnership(device.value(), getuid(),
98 sandbox_factory_.run_as().gid) ||
99 !platform()->SetPermissions(source,
100 S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP)) {
101 LOG(ERROR) << "Can't set up permissions on " << quote(source);
102 *error = MOUNT_ERROR_INSUFFICIENT_PERMISSIONS;
103 return nullptr;
104 }
105
106 std::unique_ptr<SandboxedProcess> sandbox;
107 // For tests we use injected factory.
108 if (upstream_factory_) {
109 sandbox = upstream_factory_->CreateSandboxedProcess();
110 sandbox->AddArgument(sandbox_factory_.executable().value());
111 } else {
112 sandbox = sandbox_factory_.CreateSandboxedProcess();
113 }
114
115 // Bind-mount the device into the sandbox.
116 if (!sandbox->BindMount(device.value(), device.value(), true, false)) {
117 LOG(ERROR) << "Can't bind the device " << quote(device)
118 << " into the sandbox";
119 *error = MOUNT_ERROR_INTERNAL;
120 return nullptr;
121 }
122
123 if (!options_.empty()) {
Sergei Datsenko1bb0bdc2021-02-17 11:26:43 +1100124 std::string options;
125 if (!JoinParamsIntoOptions(options_, &options)) {
126 *error = MOUNT_ERROR_INVALID_MOUNT_OPTIONS;
127 return nullptr;
128 }
Sergei Datsenko68cd43a2020-11-16 22:57:16 +1100129 sandbox->AddArgument("-o");
Sergei Datsenko1bb0bdc2021-02-17 11:26:43 +1100130 sandbox->AddArgument(options);
Sergei Datsenko68cd43a2020-11-16 22:57:16 +1100131 }
132
133 sandbox->AddArgument(device.value());
134
135 *error = MOUNT_ERROR_NONE;
136 return sandbox;
137 }
138
139 // Used to inject mocks for testing.
140 const SandboxedProcessFactory* const upstream_factory_;
141
142 const FUSESandboxedProcessFactory sandbox_factory_;
143 const std::vector<std::string> options_;
144};
145
146// Specialization of a system mounter which deals with FAT-specific
147// mount options.
148class FATMounter : public SystemMounter {
149 public:
150 FATMounter(const Platform* platform, std::vector<std::string> options)
151 : SystemMounter(
152 platform, "vfat", /* read_only= */ false, std::move(options)) {}
153
154 private:
155 MountErrorType ParseParams(
156 std::vector<std::string> params,
157 std::vector<std::string>* mount_options) const override {
158 // FAT32 stores times as local time instead of UTC. By default, the vfat
159 // kernel module will use the kernel's time zone, which is set using
160 // settimeofday(), to interpret time stamps as local time. However, time
161 // zones are complicated and generally a user-space concern in modern Linux.
162 // The man page for {get,set}timeofday comments that the |timezone| fields
163 // of these functions is obsolete. Chrome OS doesn't appear to set these
164 // either. Instead, we pass the time offset explicitly as a mount option so
165 // that the user can see file time stamps as local time. This mirrors what
166 // the user will see in other operating systems.
167 time_t now = base::Time::Now().ToTimeT();
168 struct tm timestruct;
169 // The time zone might have changed since cros-disks was started. Force a
170 // re-read of the time zone to ensure the local time is what the user
171 // expects.
172 tzset();
173 localtime_r(&now, &timestruct);
174 // tm_gmtoff is a glibc extension.
175 int64_t offset_minutes = static_cast<int64_t>(timestruct.tm_gmtoff) / 60;
176 std::string offset_option =
177 base::StringPrintf("time_offset=%" PRId64, offset_minutes);
178
179 mount_options->push_back(offset_option);
180
181 return SystemMounter::ParseParams(std::move(params), mount_options);
182 }
183};
184
Sergei Datsenko18464b92020-11-05 21:22:46 +1100185} // namespace
186
Anand K Mistryc7eba322020-01-15 17:45:38 +1100187class DiskManager::EjectingMountPoint : public MountPoint {
188 public:
189 EjectingMountPoint(std::unique_ptr<MountPoint> mount_point,
Sergei Datsenko0ba12032021-01-07 08:51:14 +1100190 const Platform* platform,
Anand K Mistryc7eba322020-01-15 17:45:38 +1100191 DiskManager* disk_manager,
192 const std::string& device_file)
Sergei Datsenko0ba12032021-01-07 08:51:14 +1100193 : MountPoint(
194 {
195 .mount_path = mount_point->path(),
196 .source = mount_point->source(),
197 .filesystem_type = mount_point->fstype(),
198 .flags = mount_point->flags(),
199 .data = mount_point->data(),
200 },
201 platform),
Anand K Mistryc7eba322020-01-15 17:45:38 +1100202 mount_point_(std::move(mount_point)),
203 disk_manager_(disk_manager),
204 device_file_(device_file) {
205 DCHECK(mount_point_);
206 DCHECK(disk_manager_);
207 DCHECK(!device_file_.empty());
208 }
209
Sergei Datsenko50c204d2020-11-14 21:18:40 +1100210 EjectingMountPoint(const EjectingMountPoint&) = delete;
211 EjectingMountPoint& operator=(const EjectingMountPoint&) = delete;
212
Sergei Datsenko0ba12032021-01-07 08:51:14 +1100213 ~EjectingMountPoint() override {}
Anand K Mistryc7eba322020-01-15 17:45:38 +1100214
215 void Release() override {
216 MountPoint::Release();
217 mount_point_->Release();
218 }
219
220 protected:
Sergei Datsenko0ba12032021-01-07 08:51:14 +1100221 MountErrorType UnmountImpl() override { return CleanUp(); }
222
223 MountErrorType RemountImpl(int flags) override {
224 return mount_point_->Remount(flags & MS_RDONLY);
225 }
226
227 private:
228 MountErrorType CleanUp() {
Anand K Mistryc7eba322020-01-15 17:45:38 +1100229 MountErrorType error = mount_point_->Unmount();
Sergei Datsenko0ba12032021-01-07 08:51:14 +1100230 if (error == MOUNT_ERROR_NONE || error == MOUNT_ERROR_PATH_NOT_MOUNTED) {
Anand K Mistryc7eba322020-01-15 17:45:38 +1100231 bool success = disk_manager_->EjectDevice(device_file_);
232 LOG_IF(ERROR, !success)
233 << "Unable to eject device " << quote(device_file_)
234 << " for mount path " << quote(path());
235 }
236 return error;
237 }
238
Anand K Mistryc7eba322020-01-15 17:45:38 +1100239 const std::unique_ptr<MountPoint> mount_point_;
240 DiskManager* const disk_manager_;
241 const std::string device_file_;
Anand K Mistryc7eba322020-01-15 17:45:38 +1100242};
243
Ben Chan213c6d92019-04-10 16:21:52 -0700244DiskManager::DiskManager(const std::string& mount_root,
Ben Chande0e3f62017-09-26 06:28:39 -0700245 Platform* platform,
246 Metrics* metrics,
Sergei Datsenkoa910bba2019-06-18 13:31:59 +1000247 brillo::ProcessReaper* process_reaper,
Sergei Datsenko16821892019-04-05 11:26:38 +1100248 DiskMonitor* disk_monitor,
Sergei Datsenko68cd43a2020-11-16 22:57:16 +1100249 DeviceEjector* device_ejector,
250 const SandboxedProcessFactory* test_sandbox_factory)
Sergei Datsenkoa910bba2019-06-18 13:31:59 +1000251 : MountManager(mount_root, platform, metrics, process_reaper),
Sergei Datsenko16821892019-04-05 11:26:38 +1100252 disk_monitor_(disk_monitor),
Ben Chan1e5a0cb2012-03-22 00:41:52 -0700253 device_ejector_(device_ejector),
Sergei Datsenko68cd43a2020-11-16 22:57:16 +1100254 test_sandbox_factory_(test_sandbox_factory),
Sergei Datsenko16821892019-04-05 11:26:38 +1100255 eject_device_on_unmount_(true) {}
Ryan Cairnsea6505f2011-04-10 19:54:53 -0700256
257DiskManager::~DiskManager() {
Ben Chana4c75062011-11-11 09:47:55 -0800258 UnmountAll();
Ryan Cairnsea6505f2011-04-10 19:54:53 -0700259}
260
Ben Chan8dcede82011-07-25 20:56:13 -0700261bool DiskManager::Initialize() {
Sergei Datsenko68cd43a2020-11-16 22:57:16 +1100262 OwnerUser run_as_exfat;
263 if (!platform()->GetUserAndGroupId("fuse-exfat", &run_as_exfat.uid,
264 &run_as_exfat.gid)) {
265 PLOG(ERROR) << "Cannot resolve fuse-exfat user";
266 return false;
267 }
268 OwnerUser run_as_ntfs;
269 if (!platform()->GetUserAndGroupId("ntfs-3g", &run_as_ntfs.uid,
270 &run_as_ntfs.gid)) {
271 PLOG(ERROR) << "Cannot resolve ntfs-3g user";
272 return false;
273 }
274
275 std::string uid = base::StringPrintf("uid=%d", kChronosUID);
276 std::string gid = base::StringPrintf("gid=%d", kChronosAccessGID);
277
278 // FAT32 - typical USB stick/SD card filesystem.
279 mounters_["vfat"] = std::make_unique<FATMounter>(
Sergei Datsenko3928f782020-12-31 09:14:04 +1100280 platform(), std::vector<std::string>{kOptionFlush, "shortname=mixed",
281 kOptionUtf8, uid, gid});
Sergei Datsenko68cd43a2020-11-16 22:57:16 +1100282
283 // Fancier newer version of FAT used for new big SD cards and USB sticks.
284 mounters_["exfat"] = std::make_unique<DiskFUSEMounter>(
285 platform(), process_reaper(), "exfat", test_sandbox_factory_,
286 SandboxedExecutable{base::FilePath("/usr/sbin/mount.exfat-fuse")},
Sergei Datsenko3928f782020-12-31 09:14:04 +1100287 run_as_exfat, std::vector<std::string>{kOptionDirSync, uid, gid});
Sergei Datsenko68cd43a2020-11-16 22:57:16 +1100288
289 // External drives and some big USB sticks would likely have NTFS.
290 mounters_["ntfs"] = std::make_unique<DiskFUSEMounter>(
291 platform(), process_reaper(), "ntfs", test_sandbox_factory_,
292 SandboxedExecutable{base::FilePath("/usr/bin/ntfs-3g")}, run_as_ntfs,
Sergei Datsenko3928f782020-12-31 09:14:04 +1100293 std::vector<std::string>{kOptionDirSync, uid, gid});
Sergei Datsenko68cd43a2020-11-16 22:57:16 +1100294
295 // Typical CD/DVD filesystem. Inherently read-only.
296 mounters_["iso9660"] = std::make_unique<SystemMounter>(
297 platform(), "iso9660", true,
Sergei Datsenko3928f782020-12-31 09:14:04 +1100298 std::vector<std::string>{kOptionUtf8, uid, gid});
Sergei Datsenko68cd43a2020-11-16 22:57:16 +1100299
300 // Newer DVD filesystem. Inherently read-only.
301 mounters_["udf"] = std::make_unique<SystemMounter>(
Sergei Datsenko3928f782020-12-31 09:14:04 +1100302 platform(), "udf", true, std::vector<std::string>{kOptionUtf8, uid, gid});
Sergei Datsenko68cd43a2020-11-16 22:57:16 +1100303
304 // MacOS's HFS+ is not properly/officially supported, but sort of works,
305 // although with severe limitaions.
306 mounters_["hfsplus"] = std::make_unique<SystemMounter>(
307 platform(), "hfsplus", false, std::vector<std::string>{uid, gid});
308
309 // Have no reasonable explanation why would one have external media
310 // with a native Linux, filesystem and use CrOS to access it, given
311 // all the problems and limitations they would face, but for compatibility
312 // with previous versions we keep it unofficially supported.
313 mounters_["ext4"] = std::make_unique<SystemMounter>(
314 platform(), "ext4", false, std::vector<std::string>{});
315 mounters_["ext3"] = std::make_unique<SystemMounter>(
316 platform(), "ext3", false, std::vector<std::string>{});
317 mounters_["ext2"] = std::make_unique<SystemMounter>(
318 platform(), "ext2", false, std::vector<std::string>{});
319
Ben Chan8dcede82011-07-25 20:56:13 -0700320 return MountManager::Initialize();
321}
322
Ben Chan213c6d92019-04-10 16:21:52 -0700323bool DiskManager::CanMount(const std::string& source_path) const {
Ben Chan8dcede82011-07-25 20:56:13 -0700324 // The following paths can be mounted:
325 // /sys/...
326 // /devices/...
327 // /dev/...
Alex Vakulenkoe50371c2016-01-20 16:06:19 -0800328 return base::StartsWith(source_path, "/sys/", base::CompareCase::SENSITIVE) ||
329 base::StartsWith(source_path, "/devices/",
330 base::CompareCase::SENSITIVE) ||
331 base::StartsWith(source_path, "/dev/", base::CompareCase::SENSITIVE);
Ben Chan8dcede82011-07-25 20:56:13 -0700332}
333
Anand K Mistryd0a05232020-01-24 14:04:18 +1100334std::unique_ptr<MountPoint> DiskManager::DoMount(
Anand K Mistryc7eba322020-01-15 17:45:38 +1100335 const std::string& source_path,
336 const std::string& filesystem_type,
337 const std::vector<std::string>& options,
338 const base::FilePath& mount_path,
Anand K Mistryc7eba322020-01-15 17:45:38 +1100339 MountErrorType* error) {
Ben Chan8dcede82011-07-25 20:56:13 -0700340 CHECK(!source_path.empty()) << "Invalid source path argument";
341 CHECK(!mount_path.empty()) << "Invalid mount path argument";
342
343 Disk disk;
Sergei Datsenko16821892019-04-05 11:26:38 +1100344 if (!disk_monitor_->GetDiskByDevicePath(base::FilePath(source_path), &disk)) {
François Degros8b4e31e2019-07-29 11:39:19 +1000345 LOG(ERROR) << quote(source_path) << " is not a valid device";
Anand K Mistryc7eba322020-01-15 17:45:38 +1100346 *error = MOUNT_ERROR_INVALID_DEVICE_PATH;
347 return nullptr;
Ben Chan8dcede82011-07-25 20:56:13 -0700348 }
349
Ben Chanf0f2bcc2017-11-10 14:59:55 -0800350 if (disk.is_on_boot_device) {
François Degros8b4e31e2019-07-29 11:39:19 +1000351 LOG(ERROR) << quote(source_path)
352 << " is on boot device and not allowed to mount";
Anand K Mistryc7eba322020-01-15 17:45:38 +1100353 *error = MOUNT_ERROR_INVALID_DEVICE_PATH;
354 return nullptr;
Ben Chanf0f2bcc2017-11-10 14:59:55 -0800355 }
356
Ben Chanff92fa32017-10-17 16:17:15 -0700357 if (disk.device_file.empty()) {
François Degros8b4e31e2019-07-29 11:39:19 +1000358 LOG(ERROR) << quote(source_path) << " does not have a device file";
Anand K Mistryc7eba322020-01-15 17:45:38 +1100359 *error = MOUNT_ERROR_INVALID_DEVICE_PATH;
360 return nullptr;
Ben Chan8dcede82011-07-25 20:56:13 -0700361 }
362
Sergei Datsenko68cd43a2020-11-16 22:57:16 +1100363 if (!platform()->PathExists(disk.device_file)) {
364 LOG(ERROR) << quote(source_path) << " has device file "
365 << quote(disk.device_file) << " which is missing";
366 *error = MOUNT_ERROR_INVALID_DEVICE_PATH;
367 return nullptr;
368 }
369
Ben Chan213c6d92019-04-10 16:21:52 -0700370 std::string device_filesystem_type =
Ben Chanff92fa32017-10-17 16:17:15 -0700371 filesystem_type.empty() ? disk.filesystem_type : filesystem_type;
372 metrics()->RecordDeviceMediaType(disk.media_type);
Ben Chan930f18d2011-11-21 09:18:50 -0800373 metrics()->RecordFilesystemType(device_filesystem_type);
Ben Chan8dcede82011-07-25 20:56:13 -0700374 if (device_filesystem_type.empty()) {
François Degros8b4e31e2019-07-29 11:39:19 +1000375 LOG(ERROR) << "Cannot determine the file system type of device "
376 << quote(source_path);
Anand K Mistryc7eba322020-01-15 17:45:38 +1100377 *error = MOUNT_ERROR_UNKNOWN_FILESYSTEM;
378 return nullptr;
Ben Chan8dcede82011-07-25 20:56:13 -0700379 }
380
Sergei Datsenko68cd43a2020-11-16 22:57:16 +1100381 auto it = mounters_.find(device_filesystem_type);
382 if (it == mounters_.end()) {
383 LOG(ERROR) << "Unsupported file system type "
384 << quote(device_filesystem_type) << " of device "
385 << quote(source_path);
Anand K Mistryc7eba322020-01-15 17:45:38 +1100386 *error = MOUNT_ERROR_UNSUPPORTED_FILESYSTEM;
387 return nullptr;
Ben Chan8dcede82011-07-25 20:56:13 -0700388 }
389
Sergei Datsenko68cd43a2020-11-16 22:57:16 +1100390 const Mounter* mounter = it->second.get();
391
392 auto applied_options = options;
393 bool media_read_only = disk.is_read_only || disk.IsOpticalDisk();
394 if (media_read_only && !IsReadOnlyMount(applied_options)) {
Sergei Datsenko3928f782020-12-31 09:14:04 +1100395 applied_options.push_back("ro");
Sergei Datsenko68cd43a2020-11-16 22:57:16 +1100396 }
Ben Chanb5d71222012-10-03 12:55:16 -0700397
Sergei Datsenko199f4f42020-10-08 10:47:12 +1100398 std::unique_ptr<MountPoint> mount_point =
Sergei Datsenko68cd43a2020-11-16 22:57:16 +1100399 mounter->Mount(disk.device_file, mount_path, applied_options, error);
Anand K Mistryc7eba322020-01-15 17:45:38 +1100400 if (*error != MOUNT_ERROR_NONE) {
401 DCHECK(!mount_point);
Sergei Datsenkoda54a072018-05-14 12:51:56 +1000402 // Try to mount the filesystem read-only if mounting it read-write failed.
Sergei Datsenko68cd43a2020-11-16 22:57:16 +1100403 if (!IsReadOnlyMount(applied_options)) {
François Degros8b4e31e2019-07-29 11:39:19 +1000404 LOG(INFO) << "Trying to mount " << quote(source_path) << " read-only";
Sergei Datsenko3928f782020-12-31 09:14:04 +1100405 applied_options.push_back("ro");
Sergei Datsenko199f4f42020-10-08 10:47:12 +1100406 mount_point =
Sergei Datsenko68cd43a2020-11-16 22:57:16 +1100407 mounter->Mount(disk.device_file, mount_path, applied_options, error);
Sergei Datsenkoda54a072018-05-14 12:51:56 +1000408 }
409 }
410
Anand K Mistryc7eba322020-01-15 17:45:38 +1100411 if (*error != MOUNT_ERROR_NONE) {
412 DCHECK(!mount_point);
413 return nullptr;
Ben Chanb5d71222012-10-03 12:55:16 -0700414 }
415
Anand K Mistryc7eba322020-01-15 17:45:38 +1100416 return MaybeWrapMountPointForEject(std::move(mount_point), disk);
Ben Chan8dcede82011-07-25 20:56:13 -0700417}
418
Ben Chan213c6d92019-04-10 16:21:52 -0700419std::string DiskManager::SuggestMountPath(
420 const std::string& source_path) const {
Ben Chan8dcede82011-07-25 20:56:13 -0700421 Disk disk;
Sergei Datsenko16821892019-04-05 11:26:38 +1100422 disk_monitor_->GetDiskByDevicePath(base::FilePath(source_path), &disk);
Ben Chan8dcede82011-07-25 20:56:13 -0700423 // If GetDiskByDevicePath fails, disk.GetPresentationName() returns
424 // the fallback presentation name.
Anand K Mistry09f2db12019-11-07 17:06:56 +1100425 return mount_root().Append(disk.GetPresentationName()).value();
Ben Chan8dcede82011-07-25 20:56:13 -0700426}
427
Ben Chanf8692882011-08-21 10:15:30 -0700428bool DiskManager::ShouldReserveMountPathOnError(
429 MountErrorType error_type) const {
Ben Chanfcb2fc02011-11-21 09:44:07 -0800430 return error_type == MOUNT_ERROR_UNKNOWN_FILESYSTEM ||
431 error_type == MOUNT_ERROR_UNSUPPORTED_FILESYSTEM;
Ben Chanf8692882011-08-21 10:15:30 -0700432}
433
Anand K Mistryc7eba322020-01-15 17:45:38 +1100434bool DiskManager::EjectDevice(const std::string& device_file) {
435 if (eject_device_on_unmount_) {
436 return device_ejector_->Eject(device_file);
437 }
Ben Chanb5d71222012-10-03 12:55:16 -0700438 return true;
439}
440
Anand K Mistryc7eba322020-01-15 17:45:38 +1100441std::unique_ptr<MountPoint> DiskManager::MaybeWrapMountPointForEject(
442 std::unique_ptr<MountPoint> mount_point, const Disk& disk) {
443 if (!disk.IsOpticalDisk()) {
444 return mount_point;
Ben Chan1e5a0cb2012-03-22 00:41:52 -0700445 }
Sergei Datsenko0ba12032021-01-07 08:51:14 +1100446 return std::make_unique<EjectingMountPoint>(
447 std::move(mount_point), platform(), this, disk.device_file);
Ben Chan1e5a0cb2012-03-22 00:41:52 -0700448}
449
450bool DiskManager::UnmountAll() {
451 // UnmountAll() is called when a user session ends. We do not want to eject
452 // devices in that situation and thus set |eject_device_on_unmount_| to
453 // false temporarily to prevent devices from being ejected upon unmount.
454 eject_device_on_unmount_ = false;
455 bool all_unmounted = MountManager::UnmountAll();
456 eject_device_on_unmount_ = true;
457 return all_unmounted;
458}
459
Ben Chanbdc39742011-05-11 17:51:26 -0700460} // namespace cros_disks