blob: 1f5353e034a2ee9b59842e0b8f43c58497e2b232 [file] [log] [blame]
Ben Chan1e5a0cb2012-03-22 00:41:52 -07001// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
Ben Chanf51ff002011-04-25 12:41:57 -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 Chan29be9152011-07-25 14:39:48 -07006
Anand K Mistry6b19a972018-09-11 11:14:59 +10007#include <stdlib.h>
Ben Chanf51ff002011-04-25 12:41:57 -07008#include <sys/mount.h>
Anand K Mistry6b19a972018-09-11 11:14:59 +10009#include <time.h>
Ben Chanbdc39742011-05-11 17:51:26 -070010
Sergei Datsenko68cd43a2020-11-16 22:57:16 +110011#include <map>
Ben Chan5e3ca672014-08-25 15:53:58 -070012#include <memory>
Anand K Mistryc7eba322020-01-15 17:45:38 +110013#include <utility>
Ben Chan5e3ca672014-08-25 15:53:58 -070014
Qijiang Fan713061e2021-03-08 15:45:12 +090015#include <base/check.h>
Sergei Datsenko3cf72cb2019-04-01 11:27:50 +110016#include <base/files/file_path.h>
Ben Chancd8fda42014-09-05 08:21:06 -070017#include <base/files/file_util.h>
Sergei Datsenko68cd43a2020-11-16 22:57:16 +110018#include <base/files/scoped_temp_dir.h>
Allen Webb57f0c052017-09-20 14:11:21 -070019#include <base/logging.h>
Qijiang Fan886c4692021-02-19 11:54:10 +090020#include <base/notreached.h>
Ben Chanb5d71222012-10-03 12:55:16 -070021#include <base/stl_util.h>
Sergei Datsenko68cd43a2020-11-16 22:57:16 +110022#include <base/strings/string_split.h>
23#include <base/strings/string_util.h>
Simon Glass2b1da092020-05-21 12:24:16 -060024#include <brillo/process/process_reaper.h>
Ben Chan1e5a0cb2012-03-22 00:41:52 -070025#include <gmock/gmock.h>
Ben Chanbdc39742011-05-11 17:51:26 -070026#include <gtest/gtest.h>
27
Ben Chan5ccd9fe2013-11-13 18:28:27 -080028#include "cros-disks/device_ejector.h"
Ben Chanbdc39742011-05-11 17:51:26 -070029#include "cros-disks/disk.h"
Ben Chan5e398a82019-04-10 16:40:43 -070030#include "cros-disks/disk_monitor.h"
Sergei Datsenko199f4f42020-10-08 10:47:12 +110031#include "cros-disks/fuse_mounter.h"
Ben Chanbe2b4a72011-11-08 13:42:23 -080032#include "cros-disks/metrics.h"
Anand K Mistryc7eba322020-01-15 17:45:38 +110033#include "cros-disks/mount_point.h"
Ben Chane31d2aa2011-06-15 13:52:59 -070034#include "cros-disks/mounter.h"
Ben Chan29be9152011-07-25 14:39:48 -070035#include "cros-disks/platform.h"
Sergei Datsenkoe8faba52020-10-06 21:45:22 +110036#include "cros-disks/system_mounter.h"
Ben Chanf51ff002011-04-25 12:41:57 -070037
Anand K Mistry40cff452019-07-30 10:24:48 +100038namespace cros_disks {
Ben Chan460439f2011-09-13 09:16:28 -070039namespace {
Ben Chanf51ff002011-04-25 12:41:57 -070040
François Degros3fe77c52020-02-20 14:44:54 +110041using testing::_;
Sergei Datsenko68cd43a2020-11-16 22:57:16 +110042using testing::AllOf;
Sergei Datsenkoe8faba52020-10-06 21:45:22 +110043using testing::Contains;
Sergei Datsenko68cd43a2020-11-16 22:57:16 +110044using testing::DoAll;
45using testing::DoDefault;
46using testing::ElementsAre;
47using testing::HasSubstr;
48using testing::Invoke;
François Degros3fe77c52020-02-20 14:44:54 +110049using testing::Return;
Sergei Datsenko68cd43a2020-11-16 22:57:16 +110050using testing::SaveArg;
Sergei Datsenkoe8faba52020-10-06 21:45:22 +110051using testing::StrEq;
François Degros3fe77c52020-02-20 14:44:54 +110052
Sergei Datsenko68cd43a2020-11-16 22:57:16 +110053const uint64_t kExpectedMountFlags =
54 MS_NODEV | MS_NOEXEC | MS_NOSUID | MS_NOSYMFOLLOW;
Ben Chan460439f2011-09-13 09:16:28 -070055
Ben Chan1e5a0cb2012-03-22 00:41:52 -070056class MockDeviceEjector : public DeviceEjector {
57 public:
Ben Chan445852f2017-10-02 23:00:16 -070058 MockDeviceEjector() : DeviceEjector(nullptr) {}
Ben Chan1e5a0cb2012-03-22 00:41:52 -070059
Ben Chan21150af2019-09-11 17:04:07 -070060 MOCK_METHOD(bool, Eject, (const std::string&), (override));
Sergei Datsenko16821892019-04-05 11:26:38 +110061};
62
Sergei Datsenko68cd43a2020-11-16 22:57:16 +110063class FakeDiskMonitor : public DiskMonitor {
Sergei Datsenko16821892019-04-05 11:26:38 +110064 public:
Sergei Datsenko68cd43a2020-11-16 22:57:16 +110065 FakeDiskMonitor() = default;
Sergei Datsenko16821892019-04-05 11:26:38 +110066
67 bool Initialize() override { return true; }
68
Sergei Datsenko68cd43a2020-11-16 22:57:16 +110069 std::vector<Disk> EnumerateDisks() const override { return disks_; }
70
71 bool GetDiskByDevicePath(const base::FilePath& path,
72 Disk* disk) const override {
73 for (const auto& d : disks_) {
74 if (d.device_file == path.value()) {
75 if (disk)
76 *disk = d;
77 return true;
78 }
79 }
80 return false;
81 }
82
83 std::vector<Disk> disks_;
Ben Chan1e5a0cb2012-03-22 00:41:52 -070084};
85
Anand K Mistry43575af2019-11-05 13:41:41 +110086class MockPlatform : public Platform {
87 public:
88 MockPlatform() = default;
89
90 MOCK_METHOD(MountErrorType,
91 Unmount,
92 (const std::string&, int),
93 (const, override));
Sergei Datsenko68cd43a2020-11-16 22:57:16 +110094
95 MOCK_METHOD(MountErrorType,
96 Mount,
97 (const std::string& source,
98 const std::string& target,
99 const std::string& filesystem_type,
100 uint64_t flags,
101 const std::string& options),
102 (const, override));
103
104 MOCK_METHOD(bool, PathExists, (const std::string& path), (const, override));
105 bool PathExistsImpl(const std::string& path) const {
106 return Platform::PathExists(path);
107 }
108
109 bool Lstat(const std::string& path,
110 base::stat_wrapper_t* out) const override {
111 if (base::StartsWith(path, "/dev/", base::CompareCase::SENSITIVE)) {
112 out->st_mode = S_IFBLK | 0640;
113 return true;
114 }
115 NOTREACHED();
116 return false;
117 }
118
119 bool SetOwnership(const std::string& path,
120 uid_t user_id,
121 gid_t group_id) const override {
122 return true;
123 }
124
125 bool SetPermissions(const std::string& path, mode_t mode) const override {
126 return true;
127 }
128
129 bool GetUserAndGroupId(const std::string& user_name,
130 uid_t* user_id,
131 gid_t* group_id) const override {
132 if (user_name == "fuse-exfat") {
133 *user_id = 111;
134 *group_id = 222;
135 return true;
136 }
137 if (user_name == "ntfs-3g") {
138 *user_id = 333;
139 *group_id = 444;
140 return true;
141 }
142 NOTREACHED();
143 return false;
144 }
Anand K Mistry43575af2019-11-05 13:41:41 +1100145};
146
Sergei Datsenko68cd43a2020-11-16 22:57:16 +1100147class MockSandboxedProcess : public SandboxedProcess {
148 public:
149 pid_t StartImpl(base::ScopedFD, base::ScopedFD, base::ScopedFD) override {
150 OnStart(arguments());
151 return 123;
152 }
153 int WaitImpl() override { return WaitNonBlockingImpl(); }
154 int WaitNonBlockingImpl() override { return 0; }
155 MOCK_METHOD(void, OnStart, (const std::vector<std::string>& args), (const));
156};
157
Anand K Mistry43575af2019-11-05 13:41:41 +1100158} // namespace
159
Sergei Datsenko68cd43a2020-11-16 22:57:16 +1100160class DiskManagerTest : public ::testing::Test, public SandboxedProcessFactory {
Ben Chan29be9152011-07-25 14:39:48 -0700161 public:
Sergei Datsenko68cd43a2020-11-16 22:57:16 +1100162 DiskManagerTest() {}
163
164 void SetUp() override {
165 CHECK(dir_.CreateUniqueTempDir());
166 ON_CALL(platform_, PathExists)
167 .WillByDefault(Invoke(&platform_, &MockPlatform::PathExistsImpl));
168 ON_CALL(platform_, PathExists("/dev/sda1")).WillByDefault(Return(true));
169 manager_ = std::make_unique<DiskManager>(dir_.GetPath().value(), &platform_,
170 &metrics_, &process_reaper_,
171 &monitor_, &ejector_, this);
172 CHECK(manager_->Initialize());
173 }
Ben Chan29be9152011-07-25 14:39:48 -0700174
Ben Chane31d2aa2011-06-15 13:52:59 -0700175 protected:
Sergei Datsenko68cd43a2020-11-16 22:57:16 +1100176 std::unique_ptr<SandboxedProcess> CreateSandboxedProcess() const override {
177 auto ptr = std::make_unique<MockSandboxedProcess>();
178 ON_CALL(*ptr, OnStart).WillByDefault(SaveArg<0>(&fuse_args_));
179 return ptr;
180 }
181
182 base::ScopedTempDir dir_;
Ben Chanbe2b4a72011-11-08 13:42:23 -0800183 Metrics metrics_;
Anand K Mistry43575af2019-11-05 13:41:41 +1100184 MockPlatform platform_;
Sergei Datsenkoa910bba2019-06-18 13:31:59 +1000185 brillo::ProcessReaper process_reaper_;
Sergei Datsenko16821892019-04-05 11:26:38 +1100186 MockDeviceEjector ejector_;
Sergei Datsenko68cd43a2020-11-16 22:57:16 +1100187 FakeDiskMonitor monitor_;
188 std::unique_ptr<DiskManager> manager_;
189 mutable std::vector<std::string> fuse_args_;
Ben Chanf51ff002011-04-25 12:41:57 -0700190};
191
Sergei Datsenko68cd43a2020-11-16 22:57:16 +1100192MATCHER_P(HasBits, bits, "") {
193 return bits == (bits & arg);
Ben Chanaf455a02013-01-08 15:29:22 -0800194}
195
Sergei Datsenko68cd43a2020-11-16 22:57:16 +1100196TEST_F(DiskManagerTest, MountBootDeviceNotAllowed) {
197 EXPECT_CALL(platform_, Mount).Times(0);
198 EXPECT_CALL(platform_, Unmount).Times(0);
199 std::string path;
200 MountErrorType err = manager_->Mount("/dev/sda1", "vfat", {}, &path);
201 EXPECT_EQ(MOUNT_ERROR_INVALID_DEVICE_PATH, err);
202 monitor_.disks_.push_back({
203 .is_on_boot_device = true,
204 .device_file = "/dev/sda1",
205 .filesystem_type = "vfat",
206 });
207 err = manager_->Mount("/dev/sda1", "vfat", {}, &path);
208 EXPECT_EQ(MOUNT_ERROR_INVALID_DEVICE_PATH, err);
Ben Chane31d2aa2011-06-15 13:52:59 -0700209}
210
Sergei Datsenko68cd43a2020-11-16 22:57:16 +1100211TEST_F(DiskManagerTest, MountNonExistingDevice) {
212 EXPECT_CALL(platform_, Mount).Times(0);
213 EXPECT_CALL(platform_, Unmount).Times(0);
214 monitor_.disks_.push_back({
215 .is_on_boot_device = false,
216 .device_file = "/dev/sda1",
217 .filesystem_type = "vfat",
218 });
219 EXPECT_CALL(platform_, PathExists("/dev/sda1")).WillRepeatedly(Return(false));
220 std::string path;
221 MountErrorType err = manager_->Mount("/dev/sda1", "vfat", {}, &path);
222 EXPECT_EQ(MOUNT_ERROR_INVALID_DEVICE_PATH, err);
223}
Ben Chane31d2aa2011-06-15 13:52:59 -0700224
Sergei Datsenko68cd43a2020-11-16 22:57:16 +1100225TEST_F(DiskManagerTest, MountUsesLabel) {
226 monitor_.disks_.push_back({
227 .is_on_boot_device = false,
228 .device_file = "/dev/sda1",
229 .filesystem_type = "vfat",
230 .label = "foo",
231 });
Ben Chane31d2aa2011-06-15 13:52:59 -0700232
Sergei Datsenko68cd43a2020-11-16 22:57:16 +1100233 std::string opts;
234 EXPECT_CALL(platform_, Mount("/dev/sda1", _, "vfat", _, _))
235 .WillOnce(DoAll(SaveArg<4>(&opts), Return(MOUNT_ERROR_NONE)));
236 std::string path;
237 MountErrorType err = manager_->Mount("/dev/sda1", "", {}, &path);
238 EXPECT_EQ(MOUNT_ERROR_NONE, err);
239 EXPECT_EQ("foo", base::FilePath(path).BaseName().value());
Ben Chane31d2aa2011-06-15 13:52:59 -0700240
Sergei Datsenko68cd43a2020-11-16 22:57:16 +1100241 EXPECT_CALL(platform_, Unmount(path, _)).WillOnce(Return(MOUNT_ERROR_NONE));
242 err = manager_->Unmount("/dev/sda1");
243 EXPECT_EQ(MOUNT_ERROR_NONE, err);
244}
245
246TEST_F(DiskManagerTest, MountFAT) {
Anand K Mistry6b19a972018-09-11 11:14:59 +1000247 // Override the time zone to make this test deterministic.
248 // This test uses AWST (Perth, Australia), which is UTC+8, as the test time
249 // zone. However, the TZ environment variable is the time to be added to local
250 // time to get to UTC, hence the negative.
251 setenv("TZ", "UTC-8", 1);
252
Sergei Datsenko68cd43a2020-11-16 22:57:16 +1100253 monitor_.disks_.push_back({
254 .is_on_boot_device = false,
255 .device_file = "/dev/sda1",
256 .filesystem_type = "vfat",
257 });
258
259 std::string opts;
260 EXPECT_CALL(platform_,
261 Mount("/dev/sda1", _, "vfat", HasBits(kExpectedMountFlags), _))
262 .WillOnce(DoAll(SaveArg<4>(&opts), Return(MOUNT_ERROR_NONE)));
263 std::string path;
264 MountErrorType err = manager_->Mount("/dev/sda1", "", {}, &path);
265 EXPECT_EQ(MOUNT_ERROR_NONE, err);
266 auto options =
267 base::SplitString(opts, ",", base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL);
268 EXPECT_THAT(options,
269 AllOf(Contains("uid=1000"), Contains("gid=1001"),
270 Contains("shortname=mixed"), Contains("time_offset=480")));
271
272 EXPECT_CALL(platform_, Unmount(path, _)).WillOnce(Return(MOUNT_ERROR_NONE));
273 err = manager_->Unmount("/dev/sda1");
274 EXPECT_EQ(MOUNT_ERROR_NONE, err);
Ben Chane31d2aa2011-06-15 13:52:59 -0700275}
276
Sergei Datsenko68cd43a2020-11-16 22:57:16 +1100277TEST_F(DiskManagerTest, MountExFAT) {
278 monitor_.disks_.push_back({
279 .is_on_boot_device = false,
280 .device_file = "/dev/sda1",
281 .filesystem_type = "exfat",
282 .label = "foo",
283 });
Anand K Mistry6b19a972018-09-11 11:14:59 +1000284
Sergei Datsenko68cd43a2020-11-16 22:57:16 +1100285 std::string opts;
286 EXPECT_CALL(platform_, Mount("/dev/sda1", _, "fuseblk.exfat",
287 HasBits(kExpectedMountFlags), _))
288 .WillOnce(DoAll(SaveArg<4>(&opts), Return(MOUNT_ERROR_NONE)));
289 std::string path;
290 MountErrorType err = manager_->Mount("/dev/sda1", "", {}, &path);
291 EXPECT_EQ(MOUNT_ERROR_NONE, err);
292 auto options =
293 base::SplitString(opts, ",", base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL);
294 EXPECT_THAT(options,
295 AllOf(Contains("user_id=1000"), Contains("group_id=1001")));
296 EXPECT_THAT(fuse_args_,
297 ElementsAre("/usr/sbin/mount.exfat-fuse", "-o",
298 HasSubstr("uid=1000,gid=1001"), "/dev/sda1", _));
Anand K Mistry6b19a972018-09-11 11:14:59 +1000299
Sergei Datsenko68cd43a2020-11-16 22:57:16 +1100300 EXPECT_CALL(platform_, Unmount(path, _)).WillOnce(Return(MOUNT_ERROR_NONE));
301 err = manager_->Unmount("/dev/sda1");
302 EXPECT_EQ(MOUNT_ERROR_NONE, err);
Anand K Mistry6b19a972018-09-11 11:14:59 +1000303}
304
Sergei Datsenko68cd43a2020-11-16 22:57:16 +1100305TEST_F(DiskManagerTest, MountNTFS) {
306 monitor_.disks_.push_back({
307 .is_on_boot_device = false,
308 .device_file = "/dev/sda1",
309 .filesystem_type = "ntfs",
310 .label = "foo",
311 });
Ben Chanb092d752011-07-13 11:44:38 -0700312
Sergei Datsenko68cd43a2020-11-16 22:57:16 +1100313 std::string opts;
314 EXPECT_CALL(platform_, Mount("/dev/sda1", _, "fuseblk.ntfs",
315 HasBits(kExpectedMountFlags), _))
316 .WillOnce(DoAll(SaveArg<4>(&opts), Return(MOUNT_ERROR_NONE)));
317 std::string path;
318 MountErrorType err = manager_->Mount("/dev/sda1", "", {}, &path);
319 EXPECT_EQ(MOUNT_ERROR_NONE, err);
320 auto options =
321 base::SplitString(opts, ",", base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL);
322 EXPECT_THAT(options,
323 AllOf(Contains("user_id=1000"), Contains("group_id=1001")));
324 EXPECT_THAT(fuse_args_,
325 ElementsAre("/usr/bin/ntfs-3g", "-o",
326 HasSubstr("uid=1000,gid=1001"), "/dev/sda1", _));
327
328 EXPECT_CALL(platform_, Unmount(path, _)).WillOnce(Return(MOUNT_ERROR_NONE));
329 err = manager_->Unmount("/dev/sda1");
330 EXPECT_EQ(MOUNT_ERROR_NONE, err);
Ben Chanb092d752011-07-13 11:44:38 -0700331}
332
Sergei Datsenko68cd43a2020-11-16 22:57:16 +1100333TEST_F(DiskManagerTest, MountCD) {
334 monitor_.disks_.push_back({
335 .is_on_boot_device = false,
336 .device_file = "/dev/sda1",
337 .filesystem_type = "iso9660",
338 .label = "foo",
339 });
Ben Chane31d2aa2011-06-15 13:52:59 -0700340
Sergei Datsenko68cd43a2020-11-16 22:57:16 +1100341 std::string opts;
342 EXPECT_CALL(platform_, Mount("/dev/sda1", _, "iso9660",
343 HasBits(kExpectedMountFlags | MS_RDONLY), _))
344 .WillOnce(DoAll(SaveArg<4>(&opts), Return(MOUNT_ERROR_NONE)));
345 std::string path;
346 MountErrorType err = manager_->Mount("/dev/sda1", "", {}, &path);
347 EXPECT_EQ(MOUNT_ERROR_NONE, err);
348 auto options =
349 base::SplitString(opts, ",", base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL);
350 EXPECT_THAT(options, AllOf(Contains("uid=1000"), Contains("gid=1001")));
Ben Chane31d2aa2011-06-15 13:52:59 -0700351
Sergei Datsenko68cd43a2020-11-16 22:57:16 +1100352 EXPECT_CALL(platform_, Unmount(path, _)).WillOnce(Return(MOUNT_ERROR_NONE));
353 err = manager_->Unmount("/dev/sda1");
354 EXPECT_EQ(MOUNT_ERROR_NONE, err);
355}
356
357TEST_F(DiskManagerTest, MountDVD) {
358 monitor_.disks_.push_back({
359 .is_on_boot_device = false,
360 .device_file = "/dev/sda1",
361 .filesystem_type = "udf",
362 .label = "foo",
363 });
364
365 std::string opts;
366 EXPECT_CALL(platform_, Mount("/dev/sda1", _, "udf",
367 HasBits(kExpectedMountFlags | MS_RDONLY), _))
368 .WillOnce(DoAll(SaveArg<4>(&opts), Return(MOUNT_ERROR_NONE)));
369 std::string path;
370 MountErrorType err = manager_->Mount("/dev/sda1", "", {}, &path);
371 EXPECT_EQ(MOUNT_ERROR_NONE, err);
372 auto options =
373 base::SplitString(opts, ",", base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL);
374 EXPECT_THAT(options, AllOf(Contains("uid=1000"), Contains("gid=1001")));
375
376 EXPECT_CALL(platform_, Unmount(path, _)).WillOnce(Return(MOUNT_ERROR_NONE));
377 err = manager_->Unmount("/dev/sda1");
378 EXPECT_EQ(MOUNT_ERROR_NONE, err);
379}
380
381TEST_F(DiskManagerTest, MountHFS) {
382 monitor_.disks_.push_back({
383 .is_on_boot_device = false,
384 .device_file = "/dev/sda1",
385 .filesystem_type = "hfsplus",
386 .label = "foo",
387 });
388
389 std::string opts;
390 EXPECT_CALL(platform_,
391 Mount("/dev/sda1", _, "hfsplus", HasBits(kExpectedMountFlags), _))
392 .WillOnce(DoAll(SaveArg<4>(&opts), Return(MOUNT_ERROR_NONE)));
393 std::string path;
394 MountErrorType err = manager_->Mount("/dev/sda1", "", {}, &path);
395 EXPECT_EQ(MOUNT_ERROR_NONE, err);
396 auto options =
397 base::SplitString(opts, ",", base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL);
398 EXPECT_THAT(options, AllOf(Contains("uid=1000"), Contains("gid=1001")));
399
400 EXPECT_CALL(platform_, Unmount(path, _)).WillOnce(Return(MOUNT_ERROR_NONE));
401 err = manager_->Unmount("/dev/sda1");
402 EXPECT_EQ(MOUNT_ERROR_NONE, err);
403}
404
405TEST_F(DiskManagerTest, MountReadOnlyMedia) {
406 monitor_.disks_.push_back({
407 .is_on_boot_device = false,
408 .is_read_only = true,
409 .device_file = "/dev/sda1",
410 .filesystem_type = "vfat",
411 .label = "foo",
412 });
413
414 std::string opts;
415 EXPECT_CALL(platform_, Mount("/dev/sda1", _, "vfat",
416 HasBits(kExpectedMountFlags | MS_RDONLY), _))
417 .WillOnce(DoAll(SaveArg<4>(&opts), Return(MOUNT_ERROR_NONE)));
418 std::string path;
419 MountErrorType err = manager_->Mount("/dev/sda1", "", {}, &path);
420 EXPECT_EQ(MOUNT_ERROR_NONE, err);
421
422 EXPECT_CALL(platform_, Unmount(path, _)).WillOnce(Return(MOUNT_ERROR_NONE));
423 err = manager_->Unmount("/dev/sda1");
424 EXPECT_EQ(MOUNT_ERROR_NONE, err);
425}
426
427TEST_F(DiskManagerTest, MountForcedReadOnly) {
428 monitor_.disks_.push_back({
429 .is_on_boot_device = false,
430 .device_file = "/dev/sda1",
431 .filesystem_type = "vfat",
432 .label = "foo",
433 });
434
435 std::string opts;
436 EXPECT_CALL(platform_, Mount("/dev/sda1", _, "vfat",
437 HasBits(kExpectedMountFlags | MS_RDONLY), _))
438 .WillOnce(DoAll(SaveArg<4>(&opts), Return(MOUNT_ERROR_NONE)));
439 std::string path;
440 MountErrorType err = manager_->Mount("/dev/sda1", "", {"ro"}, &path);
441 EXPECT_EQ(MOUNT_ERROR_NONE, err);
442
443 EXPECT_CALL(platform_, Unmount(path, _)).WillOnce(Return(MOUNT_ERROR_NONE));
444 err = manager_->Unmount("/dev/sda1");
445 EXPECT_EQ(MOUNT_ERROR_NONE, err);
446}
447
448TEST_F(DiskManagerTest, MountRetryReadOnlyIfFailed) {
449 monitor_.disks_.push_back({
450 .is_on_boot_device = false,
451 .device_file = "/dev/sda1",
452 .filesystem_type = "vfat",
453 .label = "foo",
454 });
455
456 EXPECT_CALL(platform_,
457 Mount("/dev/sda1", _, "vfat", HasBits(kExpectedMountFlags), _))
458 .WillOnce(Return(MOUNT_ERROR_PATH_NOT_MOUNTED));
459 std::string opts;
460 EXPECT_CALL(platform_, Mount("/dev/sda1", _, "vfat",
461 HasBits(kExpectedMountFlags | MS_RDONLY), _))
462 .WillOnce(DoAll(SaveArg<4>(&opts), Return(MOUNT_ERROR_NONE)));
463
464 std::string path;
465 MountErrorType err = manager_->Mount("/dev/sda1", "", {}, &path);
466 EXPECT_EQ(MOUNT_ERROR_NONE, err);
467
468 EXPECT_CALL(platform_, Unmount(path, _)).WillOnce(Return(MOUNT_ERROR_NONE));
469 err = manager_->Unmount("/dev/sda1");
470 EXPECT_EQ(MOUNT_ERROR_NONE, err);
Ben Chane31d2aa2011-06-15 13:52:59 -0700471}
472
Ben Chan8dcede82011-07-25 20:56:13 -0700473TEST_F(DiskManagerTest, CanMount) {
Sergei Datsenko68cd43a2020-11-16 22:57:16 +1100474 EXPECT_TRUE(manager_->CanMount("/dev/sda1"));
475 EXPECT_TRUE(manager_->CanMount("/devices/block/sda/sda1"));
476 EXPECT_TRUE(manager_->CanMount("/sys/devices/block/sda/sda1"));
477 EXPECT_FALSE(manager_->CanMount("/media/removable/disk1"));
478 EXPECT_FALSE(manager_->CanMount("/media/removable/disk1/"));
479 EXPECT_FALSE(manager_->CanMount("/media/removable/disk 1"));
480 EXPECT_FALSE(manager_->CanMount("/media/archive/test.zip"));
481 EXPECT_FALSE(manager_->CanMount("/media/archive/test.zip/"));
482 EXPECT_FALSE(manager_->CanMount("/media/archive/test 1.zip"));
483 EXPECT_FALSE(manager_->CanMount("/media/removable/disk1/test.zip"));
484 EXPECT_FALSE(manager_->CanMount("/media/removable/disk1/test 1.zip"));
485 EXPECT_FALSE(manager_->CanMount("/media/removable/disk1/dir1/test.zip"));
486 EXPECT_FALSE(manager_->CanMount("/media/removable/test.zip/test1.zip"));
487 EXPECT_FALSE(manager_->CanMount("/home/chronos/user/Downloads/test1.zip"));
488 EXPECT_FALSE(manager_->CanMount("/home/chronos/user/GCache/test1.zip"));
Ben Chande0e3f62017-09-26 06:28:39 -0700489 EXPECT_FALSE(
Sergei Datsenko68cd43a2020-11-16 22:57:16 +1100490 manager_->CanMount("/home/chronos"
491 "/u-0123456789abcdef0123456789abcdef01234567"
492 "/Downloads/test1.zip"));
Ben Chande0e3f62017-09-26 06:28:39 -0700493 EXPECT_FALSE(
Sergei Datsenko68cd43a2020-11-16 22:57:16 +1100494 manager_->CanMount("/home/chronos"
495 "/u-0123456789abcdef0123456789abcdef01234567"
496 "/GCache/test1.zip"));
497 EXPECT_FALSE(manager_->CanMount(""));
498 EXPECT_FALSE(manager_->CanMount("/tmp"));
499 EXPECT_FALSE(manager_->CanMount("/media/removable"));
500 EXPECT_FALSE(manager_->CanMount("/media/removable/"));
501 EXPECT_FALSE(manager_->CanMount("/media/archive"));
502 EXPECT_FALSE(manager_->CanMount("/media/archive/"));
503 EXPECT_FALSE(manager_->CanMount("/home/chronos/user/Downloads"));
504 EXPECT_FALSE(manager_->CanMount("/home/chronos/user/Downloads/"));
Ben Chan8dcede82011-07-25 20:56:13 -0700505}
506
Anand K Mistryc7eba322020-01-15 17:45:38 +1100507TEST_F(DiskManagerTest, EjectDevice) {
508 const base::FilePath kMountPath("/media/removable/disk");
Ben Chanb5d71222012-10-03 12:55:16 -0700509 Disk disk;
Ben Chanb5d71222012-10-03 12:55:16 -0700510
Sergei Datsenko0ba12032021-01-07 08:51:14 +1100511 EXPECT_CALL(platform_, Unmount).WillRepeatedly(Return(MOUNT_ERROR_NONE));
512
513 std::unique_ptr<MountPoint> mount_point =
514 std::make_unique<MountPoint>(MountPointData{kMountPath}, &platform_);
Anand K Mistryc7eba322020-01-15 17:45:38 +1100515 disk.device_file = "/dev/sda";
516 disk.media_type = DEVICE_MEDIA_USB;
517 EXPECT_CALL(ejector_, Eject("/dev/sda")).Times(0);
518 std::unique_ptr<MountPoint> wrapped_mount_point =
Sergei Datsenko68cd43a2020-11-16 22:57:16 +1100519 manager_->MaybeWrapMountPointForEject(std::move(mount_point), disk);
Anand K Mistryc7eba322020-01-15 17:45:38 +1100520 EXPECT_EQ(MOUNT_ERROR_NONE, wrapped_mount_point->Unmount());
521
Sergei Datsenko0ba12032021-01-07 08:51:14 +1100522 mount_point =
523 std::make_unique<MountPoint>(MountPointData{kMountPath}, &platform_);
Anand K Mistryc7eba322020-01-15 17:45:38 +1100524 disk.device_file = "/dev/sr0";
Ben Chanff92fa32017-10-17 16:17:15 -0700525 disk.media_type = DEVICE_MEDIA_OPTICAL_DISC;
Sergei Datsenko16821892019-04-05 11:26:38 +1100526 EXPECT_CALL(ejector_, Eject("/dev/sr0")).WillOnce(Return(true));
Anand K Mistryc7eba322020-01-15 17:45:38 +1100527 wrapped_mount_point =
Sergei Datsenko68cd43a2020-11-16 22:57:16 +1100528 manager_->MaybeWrapMountPointForEject(std::move(mount_point), disk);
Anand K Mistryc7eba322020-01-15 17:45:38 +1100529 EXPECT_EQ(MOUNT_ERROR_NONE, wrapped_mount_point->Unmount());
530
Sergei Datsenko0ba12032021-01-07 08:51:14 +1100531 mount_point =
532 std::make_unique<MountPoint>(MountPointData{kMountPath}, &platform_);
Anand K Mistryc7eba322020-01-15 17:45:38 +1100533 disk.device_file = "/dev/sr1";
534 disk.media_type = DEVICE_MEDIA_DVD;
535 EXPECT_CALL(ejector_, Eject("/dev/sr1")).WillOnce(Return(true));
536 wrapped_mount_point =
Sergei Datsenko68cd43a2020-11-16 22:57:16 +1100537 manager_->MaybeWrapMountPointForEject(std::move(mount_point), disk);
Anand K Mistryc7eba322020-01-15 17:45:38 +1100538 EXPECT_EQ(MOUNT_ERROR_NONE, wrapped_mount_point->Unmount());
Ben Chanb5d71222012-10-03 12:55:16 -0700539}
540
Anand K Mistryc7eba322020-01-15 17:45:38 +1100541TEST_F(DiskManagerTest, EjectDeviceWhenUnmountFailed) {
542 const base::FilePath kMountPath("/media/removable/disk");
Sergei Datsenko16821892019-04-05 11:26:38 +1100543 Disk disk;
544 disk.device_file = "/dev/sr0";
Anand K Mistryc7eba322020-01-15 17:45:38 +1100545 disk.media_type = DEVICE_MEDIA_OPTICAL_DISC;
546
Sergei Datsenko0ba12032021-01-07 08:51:14 +1100547 EXPECT_CALL(platform_, Unmount).WillRepeatedly(Return(MOUNT_ERROR_UNKNOWN));
548
549 std::unique_ptr<MountPoint> mount_point =
550 std::make_unique<MountPoint>(MountPointData{kMountPath}, &platform_);
Anand K Mistryc7eba322020-01-15 17:45:38 +1100551 EXPECT_CALL(ejector_, Eject("/dev/sr0")).Times(0);
552 std::unique_ptr<MountPoint> wrapped_mount_point =
Sergei Datsenko68cd43a2020-11-16 22:57:16 +1100553 manager_->MaybeWrapMountPointForEject(std::move(mount_point), disk);
Anand K Mistryc7eba322020-01-15 17:45:38 +1100554 EXPECT_EQ(MOUNT_ERROR_UNKNOWN, wrapped_mount_point->Unmount());
Ben Chanb5d71222012-10-03 12:55:16 -0700555}
556
Anand K Mistryc7eba322020-01-15 17:45:38 +1100557TEST_F(DiskManagerTest, EjectDeviceWhenExplicitlyDisabled) {
558 const base::FilePath kMountPath("/media/removable/disk");
Sergei Datsenko16821892019-04-05 11:26:38 +1100559 Disk disk;
560 disk.device_file = "/dev/sr0";
Anand K Mistryc7eba322020-01-15 17:45:38 +1100561 disk.media_type = DEVICE_MEDIA_OPTICAL_DISC;
562
Sergei Datsenko0ba12032021-01-07 08:51:14 +1100563 EXPECT_CALL(platform_, Unmount).WillOnce(Return(MOUNT_ERROR_NONE));
564
565 std::unique_ptr<MountPoint> mount_point =
566 std::make_unique<MountPoint>(MountPointData{kMountPath}, &platform_);
Sergei Datsenko68cd43a2020-11-16 22:57:16 +1100567 manager_->eject_device_on_unmount_ = false;
Anand K Mistryc7eba322020-01-15 17:45:38 +1100568 EXPECT_CALL(ejector_, Eject("/dev/sr0")).Times(0);
569 std::unique_ptr<MountPoint> wrapped_mount_point =
Sergei Datsenko68cd43a2020-11-16 22:57:16 +1100570 manager_->MaybeWrapMountPointForEject(std::move(mount_point), disk);
Anand K Mistryc7eba322020-01-15 17:45:38 +1100571 EXPECT_EQ(MOUNT_ERROR_NONE, wrapped_mount_point->Unmount());
Ben Chanb5d71222012-10-03 12:55:16 -0700572}
573
Anand K Mistryc7eba322020-01-15 17:45:38 +1100574TEST_F(DiskManagerTest, EjectDeviceWhenReleased) {
575 const base::FilePath kMountPath("/media/removable/disk");
576 Disk disk;
577 disk.device_file = "/dev/sr0";
578 disk.media_type = DEVICE_MEDIA_OPTICAL_DISC;
579
Sergei Datsenko0ba12032021-01-07 08:51:14 +1100580 EXPECT_CALL(platform_, Unmount).Times(0);
581
582 std::unique_ptr<MountPoint> mount_point =
583 std::make_unique<MountPoint>(MountPointData{kMountPath}, &platform_);
Anand K Mistryc7eba322020-01-15 17:45:38 +1100584 EXPECT_CALL(ejector_, Eject("/dev/sr0")).Times(0);
585 std::unique_ptr<MountPoint> wrapped_mount_point =
Sergei Datsenko68cd43a2020-11-16 22:57:16 +1100586 manager_->MaybeWrapMountPointForEject(std::move(mount_point), disk);
Anand K Mistryc7eba322020-01-15 17:45:38 +1100587 wrapped_mount_point->Release();
588 EXPECT_EQ(MOUNT_ERROR_PATH_NOT_MOUNTED, wrapped_mount_point->Unmount());
Ben Chan1e5a0cb2012-03-22 00:41:52 -0700589}
590
Ben Chanf51ff002011-04-25 12:41:57 -0700591} // namespace cros_disks