Ben Chan | 1e5a0cb | 2012-03-22 00:41:52 -0700 | [diff] [blame] | 1 | // Copyright (c) 2012 The Chromium OS Authors. All rights reserved. |
Ben Chan | 8dcede8 | 2011-07-25 20:56:13 -0700 | [diff] [blame] | 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
Ben Chan | d30e743 | 2011-11-28 13:43:17 -0800 | [diff] [blame] | 5 | // Implements cros-disks::MountManager. See mount-manager.h for details. |
| 6 | |
Ben Chan | 5ccd9fe | 2013-11-13 18:28:27 -0800 | [diff] [blame] | 7 | #include "cros-disks/mount_manager.h" |
Ben Chan | 8dcede8 | 2011-07-25 20:56:13 -0700 | [diff] [blame] | 8 | |
| 9 | #include <sys/mount.h> |
| 10 | #include <unistd.h> |
| 11 | |
| 12 | #include <algorithm> |
Sergei Datsenko | 7e7c764 | 2021-01-08 19:15:34 +1100 | [diff] [blame] | 13 | #include <unordered_set> |
Ben Chan | 632c9f8 | 2011-10-11 12:22:16 -0700 | [diff] [blame] | 14 | #include <utility> |
Ben Chan | 8dcede8 | 2011-07-25 20:56:13 -0700 | [diff] [blame] | 15 | |
Qijiang Fan | 713061e | 2021-03-08 15:45:12 +0900 | [diff] [blame] | 16 | #include <base/check.h> |
Ben Chan | 97e20d4 | 2014-02-05 18:38:07 -0800 | [diff] [blame] | 17 | #include <base/files/file_path.h> |
Sergei Datsenko | 0f014d2 | 2018-04-04 16:37:22 +1000 | [diff] [blame] | 18 | #include <base/files/file_util.h> |
Ben Chan | 8dcede8 | 2011-07-25 20:56:13 -0700 | [diff] [blame] | 19 | #include <base/logging.h> |
Mike Frysinger | 38ae98d | 2012-04-11 12:03:44 -0400 | [diff] [blame] | 20 | #include <base/stl_util.h> |
Ben Chan | 97e20d4 | 2014-02-05 18:38:07 -0800 | [diff] [blame] | 21 | #include <base/strings/string_util.h> |
Ben Chan | 8dcede8 | 2011-07-25 20:56:13 -0700 | [diff] [blame] | 22 | |
François Degros | bf7bb59 | 2019-07-12 09:49:52 +1000 | [diff] [blame] | 23 | #include "cros-disks/error_logger.h" |
Tatsuhisa Yamaguchi | 5a6a303 | 2016-08-19 20:03:54 +0900 | [diff] [blame] | 24 | #include "cros-disks/mount_options.h" |
Anand K Mistry | e9a60fb | 2019-11-07 16:41:03 +1100 | [diff] [blame] | 25 | #include "cros-disks/mounter.h" |
Ben Chan | 32e4b4b | 2014-07-23 16:18:37 -0700 | [diff] [blame] | 26 | #include "cros-disks/platform.h" |
François Degros | 8b4e31e | 2019-07-29 11:39:19 +1000 | [diff] [blame] | 27 | #include "cros-disks/quote.h" |
Sergei Datsenko | bcd8e46 | 2018-04-20 15:44:56 +1000 | [diff] [blame] | 28 | #include "cros-disks/uri.h" |
Ben Chan | 8dcede8 | 2011-07-25 20:56:13 -0700 | [diff] [blame] | 29 | |
Anand K Mistry | 40cff45 | 2019-07-30 10:24:48 +1000 | [diff] [blame] | 30 | namespace cros_disks { |
Ben Chan | 460439f | 2011-09-13 09:16:28 -0700 | [diff] [blame] | 31 | namespace { |
Ben Chan | 8dcede8 | 2011-07-25 20:56:13 -0700 | [diff] [blame] | 32 | |
Ben Chan | 9ed09e3 | 2011-11-22 16:24:06 -0800 | [diff] [blame] | 33 | // Permissions to set on the mount root directory (u+rwx,og+rx). |
Ben Chan | 460439f | 2011-09-13 09:16:28 -0700 | [diff] [blame] | 34 | const mode_t kMountRootDirectoryPermissions = |
Ben Chan | 8dcede8 | 2011-07-25 20:56:13 -0700 | [diff] [blame] | 35 | S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH; |
Ben Chan | 09c90d0 | 2012-04-25 22:09:09 -0700 | [diff] [blame] | 36 | // Prefix of the mount label option. |
Sergei Datsenko | 7e7c764 | 2021-01-08 19:15:34 +1100 | [diff] [blame] | 37 | const char kMountOptionMountLabelPrefix[] = "mountlabel"; |
Tatsuhisa Yamaguchi | b670bd1 | 2016-09-28 23:06:44 +0900 | [diff] [blame] | 38 | // Literal for mount option: "remount". |
| 39 | const char kMountOptionRemount[] = "remount"; |
Ben Chan | 9ed09e3 | 2011-11-22 16:24:06 -0800 | [diff] [blame] | 40 | // Maximum number of trials on creating a mount directory using |
| 41 | // Platform::CreateOrReuseEmptyDirectoryWithFallback(). |
Ben Chan | d30e743 | 2011-11-28 13:43:17 -0800 | [diff] [blame] | 42 | // A value of 100 seems reasonable and enough to handle directory name |
| 43 | // collisions under common scenarios. |
| 44 | const unsigned kMaxNumMountTrials = 100; |
Ben Chan | 460439f | 2011-09-13 09:16:28 -0700 | [diff] [blame] | 45 | |
| 46 | } // namespace |
| 47 | |
Ben Chan | 213c6d9 | 2019-04-10 16:21:52 -0700 | [diff] [blame] | 48 | MountManager::MountManager(const std::string& mount_root, |
Ben Chan | de0e3f6 | 2017-09-26 06:28:39 -0700 | [diff] [blame] | 49 | Platform* platform, |
Sergei Datsenko | a910bba | 2019-06-18 13:31:59 +1000 | [diff] [blame] | 50 | Metrics* metrics, |
| 51 | brillo::ProcessReaper* process_reaper) |
Anand K Mistry | 09f2db1 | 2019-11-07 17:06:56 +1100 | [diff] [blame] | 52 | : mount_root_(base::FilePath(mount_root)), |
Sergei Datsenko | a910bba | 2019-06-18 13:31:59 +1000 | [diff] [blame] | 53 | platform_(platform), |
| 54 | metrics_(metrics), |
| 55 | process_reaper_(process_reaper) { |
Ben Chan | 8dcede8 | 2011-07-25 20:56:13 -0700 | [diff] [blame] | 56 | CHECK(!mount_root_.empty()) << "Invalid mount root directory"; |
Anand K Mistry | 09f2db1 | 2019-11-07 17:06:56 +1100 | [diff] [blame] | 57 | CHECK(mount_root_.IsAbsolute()) << "Mount root not absolute path"; |
Ben Chan | 8dcede8 | 2011-07-25 20:56:13 -0700 | [diff] [blame] | 58 | CHECK(platform_) << "Invalid platform object"; |
Ben Chan | be2b4a7 | 2011-11-08 13:42:23 -0800 | [diff] [blame] | 59 | CHECK(metrics_) << "Invalid metrics object"; |
Ben Chan | 8dcede8 | 2011-07-25 20:56:13 -0700 | [diff] [blame] | 60 | } |
| 61 | |
| 62 | MountManager::~MountManager() { |
Ben Chan | a4c7506 | 2011-11-11 09:47:55 -0800 | [diff] [blame] | 63 | // UnmountAll() should be called from a derived class instead of this base |
Anand K Mistry | 2481ce8 | 2020-01-24 14:46:53 +1100 | [diff] [blame] | 64 | // class as UnmountAll() calls MountPoint::Unmount() which may call back into |
| 65 | // a derived class. |
Ben Chan | 8dcede8 | 2011-07-25 20:56:13 -0700 | [diff] [blame] | 66 | } |
| 67 | |
| 68 | bool MountManager::Initialize() { |
Anand K Mistry | 09f2db1 | 2019-11-07 17:06:56 +1100 | [diff] [blame] | 69 | return platform_->CreateDirectory(mount_root_.value()) && |
| 70 | platform_->SetOwnership(mount_root_.value(), getuid(), getgid()) && |
| 71 | platform_->SetPermissions(mount_root_.value(), |
| 72 | kMountRootDirectoryPermissions); |
Ben Chan | 8dcede8 | 2011-07-25 20:56:13 -0700 | [diff] [blame] | 73 | } |
| 74 | |
Ben Chan | b3bf8d1 | 2013-04-23 13:57:55 -0700 | [diff] [blame] | 75 | bool MountManager::StartSession() { |
Ben Chan | 8dcede8 | 2011-07-25 20:56:13 -0700 | [diff] [blame] | 76 | return true; |
| 77 | } |
| 78 | |
Ben Chan | b3bf8d1 | 2013-04-23 13:57:55 -0700 | [diff] [blame] | 79 | bool MountManager::StopSession() { |
Sam McNally | 8a71c5c | 2019-03-15 15:51:37 +1100 | [diff] [blame] | 80 | return UnmountAll(); |
Ben Chan | 8dcede8 | 2011-07-25 20:56:13 -0700 | [diff] [blame] | 81 | } |
| 82 | |
Ben Chan | 213c6d9 | 2019-04-10 16:21:52 -0700 | [diff] [blame] | 83 | MountErrorType MountManager::Mount(const std::string& source_path, |
| 84 | const std::string& filesystem_type, |
Sergei Datsenko | 7e7c764 | 2021-01-08 19:15:34 +1100 | [diff] [blame] | 85 | std::vector<std::string> options, |
Ben Chan | 213c6d9 | 2019-04-10 16:21:52 -0700 | [diff] [blame] | 86 | std::string* mount_path) { |
Sergei Datsenko | 0f014d2 | 2018-04-04 16:37:22 +1000 | [diff] [blame] | 87 | // Source is not necessary a path, but if it is let's resolve it to |
| 88 | // some real underlying object. |
Ben Chan | 213c6d9 | 2019-04-10 16:21:52 -0700 | [diff] [blame] | 89 | std::string real_path; |
Jorge Lucangeli Obes | 0a388a2 | 2020-04-06 11:43:21 -0400 | [diff] [blame] | 90 | if (Uri::IsUri(source_path) || !ResolvePath(source_path, &real_path)) { |
Sergei Datsenko | 0f014d2 | 2018-04-04 16:37:22 +1000 | [diff] [blame] | 91 | real_path = source_path; |
| 92 | } |
| 93 | |
| 94 | if (real_path.empty()) { |
| 95 | LOG(ERROR) << "Failed to mount an invalid path"; |
Ben Chan | fcb2fc0 | 2011-11-21 09:44:07 -0800 | [diff] [blame] | 96 | return MOUNT_ERROR_INVALID_ARGUMENT; |
Ben Chan | 8dcede8 | 2011-07-25 20:56:13 -0700 | [diff] [blame] | 97 | } |
| 98 | if (!mount_path) { |
| 99 | LOG(ERROR) << "Invalid mount path argument"; |
Ben Chan | fcb2fc0 | 2011-11-21 09:44:07 -0800 | [diff] [blame] | 100 | return MOUNT_ERROR_INVALID_ARGUMENT; |
Ben Chan | 8dcede8 | 2011-07-25 20:56:13 -0700 | [diff] [blame] | 101 | } |
| 102 | |
Sergei Datsenko | 7e7c764 | 2021-01-08 19:15:34 +1100 | [diff] [blame] | 103 | if (RemoveParamsEqualTo(&options, kMountOptionRemount) == 0) { |
| 104 | return MountNewSource(real_path, filesystem_type, std::move(options), |
| 105 | mount_path); |
Tatsuhisa Yamaguchi | b670bd1 | 2016-09-28 23:06:44 +0900 | [diff] [blame] | 106 | } else { |
Sergei Datsenko | 7e7c764 | 2021-01-08 19:15:34 +1100 | [diff] [blame] | 107 | return Remount(real_path, filesystem_type, std::move(options), mount_path); |
Tatsuhisa Yamaguchi | b670bd1 | 2016-09-28 23:06:44 +0900 | [diff] [blame] | 108 | } |
| 109 | } |
| 110 | |
Ben Chan | 213c6d9 | 2019-04-10 16:21:52 -0700 | [diff] [blame] | 111 | MountErrorType MountManager::Remount(const std::string& source_path, |
Sergei Datsenko | 7e7c764 | 2021-01-08 19:15:34 +1100 | [diff] [blame] | 112 | const std::string& /*filesystem_type*/, |
| 113 | std::vector<std::string> options, |
Ben Chan | 213c6d9 | 2019-04-10 16:21:52 -0700 | [diff] [blame] | 114 | std::string* mount_path) { |
Sergei Datsenko | 7e7c764 | 2021-01-08 19:15:34 +1100 | [diff] [blame] | 115 | MountPoint* mount_point = FindMountBySource(source_path); |
| 116 | if (!mount_point) { |
François Degros | 8b4e31e | 2019-07-29 11:39:19 +1000 | [diff] [blame] | 117 | LOG(WARNING) << "Path " << quote(source_path) << " is not mounted yet"; |
Tatsuhisa Yamaguchi | b670bd1 | 2016-09-28 23:06:44 +0900 | [diff] [blame] | 118 | return MOUNT_ERROR_PATH_NOT_MOUNTED; |
| 119 | } |
| 120 | |
Sergei Datsenko | 7e7c764 | 2021-01-08 19:15:34 +1100 | [diff] [blame] | 121 | bool read_only = IsReadOnlyMount(options); |
Tatsuhisa Yamaguchi | b670bd1 | 2016-09-28 23:06:44 +0900 | [diff] [blame] | 122 | |
| 123 | // Perform the underlying mount operation. |
Sergei Datsenko | 7e7c764 | 2021-01-08 19:15:34 +1100 | [diff] [blame] | 124 | MountErrorType error_type = mount_point->Remount(read_only); |
Tatsuhisa Yamaguchi | b670bd1 | 2016-09-28 23:06:44 +0900 | [diff] [blame] | 125 | if (error_type != MOUNT_ERROR_NONE) { |
Sergei Datsenko | 0ba1203 | 2021-01-07 08:51:14 +1100 | [diff] [blame] | 126 | LOG(ERROR) << "Cannot remount path " << quote(source_path) << ": " |
| 127 | << error_type; |
Tatsuhisa Yamaguchi | b670bd1 | 2016-09-28 23:06:44 +0900 | [diff] [blame] | 128 | return error_type; |
| 129 | } |
| 130 | |
Sergei Datsenko | 7e7c764 | 2021-01-08 19:15:34 +1100 | [diff] [blame] | 131 | *mount_path = mount_point->path().value(); |
François Degros | 8b4e31e | 2019-07-29 11:39:19 +1000 | [diff] [blame] | 132 | LOG(INFO) << "Path " << quote(source_path) << " on " << quote(*mount_path) |
Sergei Datsenko | 3928f78 | 2020-12-31 09:14:04 +1100 | [diff] [blame] | 133 | << " is remounted"; |
Tatsuhisa Yamaguchi | b670bd1 | 2016-09-28 23:06:44 +0900 | [diff] [blame] | 134 | return error_type; |
| 135 | } |
| 136 | |
Sergei Datsenko | 7e7c764 | 2021-01-08 19:15:34 +1100 | [diff] [blame] | 137 | MountErrorType MountManager::MountNewSource(const std::string& source_path, |
| 138 | const std::string& filesystem_type, |
| 139 | std::vector<std::string> options, |
| 140 | std::string* mount_path) { |
| 141 | MountPoint* mp = FindMountBySource(source_path); |
| 142 | if (mp) { |
| 143 | // TODO(dats): Some obscure legacy. Why is this even needed? |
| 144 | if (mount_path->empty() || mp->path().value() == *mount_path) { |
François Degros | c309d93 | 2021-02-04 15:12:30 +1100 | [diff] [blame] | 145 | LOG(WARNING) << "Source " << redact(source_path) |
| 146 | << " is already mounted to " << redact(mp->path()); |
Sergei Datsenko | 7e7c764 | 2021-01-08 19:15:34 +1100 | [diff] [blame] | 147 | *mount_path = mp->path().value(); |
| 148 | return GetMountErrorOfReservedMountPath(mp->path()); |
Ben Chan | 8dcede8 | 2011-07-25 20:56:13 -0700 | [diff] [blame] | 149 | } |
François Degros | c309d93 | 2021-02-04 15:12:30 +1100 | [diff] [blame] | 150 | LOG(ERROR) << "Source " << redact(source_path) << " is already mounted to " |
| 151 | << redact(mp->path()); |
Sergei Datsenko | 7e7c764 | 2021-01-08 19:15:34 +1100 | [diff] [blame] | 152 | return MOUNT_ERROR_PATH_ALREADY_MOUNTED; |
Ben Chan | 8dcede8 | 2011-07-25 20:56:13 -0700 | [diff] [blame] | 153 | } |
| 154 | |
Ben Chan | 213c6d9 | 2019-04-10 16:21:52 -0700 | [diff] [blame] | 155 | std::string mount_label; |
Sergei Datsenko | 7e7c764 | 2021-01-08 19:15:34 +1100 | [diff] [blame] | 156 | if (GetParamValue(options, kMountOptionMountLabelPrefix, &mount_label)) { |
| 157 | RemoveParamsWithSameName(&options, kMountOptionMountLabelPrefix); |
| 158 | } |
Ben Chan | 09c90d0 | 2012-04-25 22:09:09 -0700 | [diff] [blame] | 159 | |
Ben Chan | d30e743 | 2011-11-28 13:43:17 -0800 | [diff] [blame] | 160 | // Create a directory and set up its ownership/permissions for mounting |
| 161 | // the source path. If an error occurs, ShouldReserveMountPathOnError() |
| 162 | // is not called to reserve the mount path as a reserved mount path still |
| 163 | // requires a proper mount directory. |
Sergei Datsenko | 7e7c764 | 2021-01-08 19:15:34 +1100 | [diff] [blame] | 164 | base::FilePath actual_mount_path(*mount_path); |
| 165 | MountErrorType error = |
| 166 | CreateMountPathForSource(source_path, mount_label, &actual_mount_path); |
| 167 | if (error != MOUNT_ERROR_NONE) { |
| 168 | return error; |
Ben Chan | 8dcede8 | 2011-07-25 20:56:13 -0700 | [diff] [blame] | 169 | } |
| 170 | |
Ben Chan | d30e743 | 2011-11-28 13:43:17 -0800 | [diff] [blame] | 171 | // Perform the underlying mount operation. If an error occurs, |
| 172 | // ShouldReserveMountPathOnError() is called to check if the mount path |
| 173 | // should be reserved. |
Anand K Mistry | f41a696 | 2019-12-19 17:41:04 +1100 | [diff] [blame] | 174 | MountErrorType error_type = MOUNT_ERROR_UNKNOWN; |
Nigel Tao | ca7a4ef | 2021-05-14 11:44:25 +1000 | [diff] [blame] | 175 | std::unique_ptr<MountPoint> mount_point = |
| 176 | DoMount(source_path, filesystem_type, std::move(options), |
| 177 | base::FilePath(actual_mount_path), &error_type); |
Ben Chan | fcb2fc0 | 2011-11-21 09:44:07 -0800 | [diff] [blame] | 178 | if (error_type == MOUNT_ERROR_NONE) { |
François Degros | 8b4e31e | 2019-07-29 11:39:19 +1000 | [diff] [blame] | 179 | LOG(INFO) << "Path " << quote(source_path) << " is mounted to " |
| 180 | << quote(actual_mount_path); |
Anand K Mistry | f41a696 | 2019-12-19 17:41:04 +1100 | [diff] [blame] | 181 | DCHECK(mount_point); |
Ben Chan | f869288 | 2011-08-21 10:15:30 -0700 | [diff] [blame] | 182 | } else if (ShouldReserveMountPathOnError(error_type)) { |
François Degros | 8b4e31e | 2019-07-29 11:39:19 +1000 | [diff] [blame] | 183 | LOG(INFO) << "Reserving mount path " << quote(actual_mount_path) << " for " |
| 184 | << quote(source_path); |
Anand K Mistry | f41a696 | 2019-12-19 17:41:04 +1100 | [diff] [blame] | 185 | DCHECK(!mount_point); |
Ben Chan | 632c9f8 | 2011-10-11 12:22:16 -0700 | [diff] [blame] | 186 | ReserveMountPath(actual_mount_path, error_type); |
Sergei Datsenko | 7e7c764 | 2021-01-08 19:15:34 +1100 | [diff] [blame] | 187 | // Create dummy mount point to associate with the mount path. |
Anand K Mistry | f1bd086 | 2019-12-20 11:54:55 +1100 | [diff] [blame] | 188 | mount_point = MountPoint::CreateLeaking(base::FilePath(actual_mount_path)); |
Ben Chan | 8dcede8 | 2011-07-25 20:56:13 -0700 | [diff] [blame] | 189 | } else { |
François Degros | ca45086 | 2021-01-14 14:40:02 +1100 | [diff] [blame] | 190 | LOG(ERROR) << "Cannot mount " << redact(source_path) << " of type " |
| 191 | << quote(filesystem_type) << ": " << error_type; |
Sergei Datsenko | 7e7c764 | 2021-01-08 19:15:34 +1100 | [diff] [blame] | 192 | platform_->RemoveEmptyDirectory(actual_mount_path.value()); |
Ben Chan | f869288 | 2011-08-21 10:15:30 -0700 | [diff] [blame] | 193 | return error_type; |
Ben Chan | 8dcede8 | 2011-07-25 20:56:13 -0700 | [diff] [blame] | 194 | } |
Ben Chan | f869288 | 2011-08-21 10:15:30 -0700 | [diff] [blame] | 195 | |
Sergei Datsenko | 7e7c764 | 2021-01-08 19:15:34 +1100 | [diff] [blame] | 196 | mount_states_.insert({source_path, std::move(mount_point)}); |
| 197 | *mount_path = actual_mount_path.value(); |
Ben Chan | 8dcede8 | 2011-07-25 20:56:13 -0700 | [diff] [blame] | 198 | return error_type; |
| 199 | } |
| 200 | |
Anand K Mistry | 5a6d5fa | 2019-11-05 17:21:48 +1100 | [diff] [blame] | 201 | MountErrorType MountManager::Unmount(const std::string& path) { |
Ben Chan | 9ed09e3 | 2011-11-22 16:24:06 -0800 | [diff] [blame] | 202 | // Determine whether the path is a source path or a mount path. |
François Degros | a9d3905 | 2020-02-20 12:20:00 +1100 | [diff] [blame] | 203 | // Is path a source path? |
Sergei Datsenko | 7e7c764 | 2021-01-08 19:15:34 +1100 | [diff] [blame] | 204 | MountPoint* mount_point = FindMountBySource(path); |
| 205 | if (!mount_point) { |
François Degros | a9d3905 | 2020-02-20 12:20:00 +1100 | [diff] [blame] | 206 | // Not a source path. Is path a mount path? |
Sergei Datsenko | 7e7c764 | 2021-01-08 19:15:34 +1100 | [diff] [blame] | 207 | mount_point = FindMountByMountPath(base::FilePath(path)); |
| 208 | if (!mount_point) { |
François Degros | a9d3905 | 2020-02-20 12:20:00 +1100 | [diff] [blame] | 209 | // Not a mount path either. |
Ben Chan | fcb2fc0 | 2011-11-21 09:44:07 -0800 | [diff] [blame] | 210 | return MOUNT_ERROR_PATH_NOT_MOUNTED; |
Ben Chan | 8dcede8 | 2011-07-25 20:56:13 -0700 | [diff] [blame] | 211 | } |
Ben Chan | 8dcede8 | 2011-07-25 20:56:13 -0700 | [diff] [blame] | 212 | } |
| 213 | |
Ben Chan | fcb2fc0 | 2011-11-21 09:44:07 -0800 | [diff] [blame] | 214 | MountErrorType error_type = MOUNT_ERROR_NONE; |
Sergei Datsenko | 7e7c764 | 2021-01-08 19:15:34 +1100 | [diff] [blame] | 215 | if (IsMountPathReserved(mount_point->path())) { |
| 216 | LOG(INFO) << "Removing mount path '" << mount_point->path() |
Ben Chan | f869288 | 2011-08-21 10:15:30 -0700 | [diff] [blame] | 217 | << "' from the reserved list"; |
Sergei Datsenko | 7e7c764 | 2021-01-08 19:15:34 +1100 | [diff] [blame] | 218 | UnreserveMountPath(mount_point->path()); |
Ben Chan | 8dcede8 | 2011-07-25 20:56:13 -0700 | [diff] [blame] | 219 | } else { |
Anand K Mistry | e9a60fb | 2019-11-07 16:41:03 +1100 | [diff] [blame] | 220 | error_type = mount_point->Unmount(); |
Sergei Datsenko | 2879b5c | 2019-09-26 13:47:40 +1000 | [diff] [blame] | 221 | |
François Degros | a9d3905 | 2020-02-20 12:20:00 +1100 | [diff] [blame] | 222 | switch (error_type) { |
| 223 | case MOUNT_ERROR_NONE: |
Sergei Datsenko | 7e7c764 | 2021-01-08 19:15:34 +1100 | [diff] [blame] | 224 | LOG(INFO) << "Unmounted " << quote(mount_point->path()); |
François Degros | a9d3905 | 2020-02-20 12:20:00 +1100 | [diff] [blame] | 225 | break; |
François Degros | 9a391e1 | 2019-07-19 15:23:23 +1000 | [diff] [blame] | 226 | |
François Degros | a9d3905 | 2020-02-20 12:20:00 +1100 | [diff] [blame] | 227 | case MOUNT_ERROR_PATH_NOT_MOUNTED: |
Sergei Datsenko | 7e7c764 | 2021-01-08 19:15:34 +1100 | [diff] [blame] | 228 | LOG(WARNING) << "Not mounted " << quote(mount_point->path()); |
François Degros | a9d3905 | 2020-02-20 12:20:00 +1100 | [diff] [blame] | 229 | break; |
| 230 | |
| 231 | default: |
Sergei Datsenko | 7e7c764 | 2021-01-08 19:15:34 +1100 | [diff] [blame] | 232 | LOG(ERROR) << "Cannot unmount " << quote(mount_point->path()) << ": " |
François Degros | a9d3905 | 2020-02-20 12:20:00 +1100 | [diff] [blame] | 233 | << error_type; |
| 234 | return error_type; |
Sergei Datsenko | 2879b5c | 2019-09-26 13:47:40 +1000 | [diff] [blame] | 235 | } |
Ben Chan | 8dcede8 | 2011-07-25 20:56:13 -0700 | [diff] [blame] | 236 | } |
Ben Chan | f869288 | 2011-08-21 10:15:30 -0700 | [diff] [blame] | 237 | |
Sergei Datsenko | 7e7c764 | 2021-01-08 19:15:34 +1100 | [diff] [blame] | 238 | platform_->RemoveEmptyDirectory(mount_point->path().value()); |
| 239 | for (auto it = mount_states_.begin(); it != mount_states_.end(); ++it) { |
| 240 | if (it->second.get() == mount_point) { |
| 241 | mount_states_.erase(it); |
| 242 | break; |
| 243 | } |
| 244 | } |
Ben Chan | 8dcede8 | 2011-07-25 20:56:13 -0700 | [diff] [blame] | 245 | return error_type; |
| 246 | } |
| 247 | |
| 248 | bool MountManager::UnmountAll() { |
| 249 | bool all_umounted = true; |
Anand K Mistry | e9a60fb | 2019-11-07 16:41:03 +1100 | [diff] [blame] | 250 | |
Sergei Datsenko | 7e7c764 | 2021-01-08 19:15:34 +1100 | [diff] [blame] | 251 | // Enumerate all the mount paths and then unmount, as calling Unmount() |
Anand K Mistry | e9a60fb | 2019-11-07 16:41:03 +1100 | [diff] [blame] | 252 | // modifies the cache. |
Sergei Datsenko | 7e7c764 | 2021-01-08 19:15:34 +1100 | [diff] [blame] | 253 | |
| 254 | std::vector<std::string> paths; |
| 255 | paths.reserve(mount_states_.size()); |
François Degros | a9d3905 | 2020-02-20 12:20:00 +1100 | [diff] [blame] | 256 | for (const auto& entry : mount_states_) { |
Sergei Datsenko | 7e7c764 | 2021-01-08 19:15:34 +1100 | [diff] [blame] | 257 | paths.push_back(entry.second->path().value()); |
Anand K Mistry | e9a60fb | 2019-11-07 16:41:03 +1100 | [diff] [blame] | 258 | } |
| 259 | |
Sergei Datsenko | 7e7c764 | 2021-01-08 19:15:34 +1100 | [diff] [blame] | 260 | for (const auto& source_path : paths) { |
Anand K Mistry | e9a60fb | 2019-11-07 16:41:03 +1100 | [diff] [blame] | 261 | if (Unmount(source_path) != MOUNT_ERROR_NONE) { |
Ben Chan | 8dcede8 | 2011-07-25 20:56:13 -0700 | [diff] [blame] | 262 | all_umounted = false; |
| 263 | } |
| 264 | } |
François Degros | a9d3905 | 2020-02-20 12:20:00 +1100 | [diff] [blame] | 265 | |
Ben Chan | 8dcede8 | 2011-07-25 20:56:13 -0700 | [diff] [blame] | 266 | return all_umounted; |
| 267 | } |
| 268 | |
Sergei Datsenko | 7e7c764 | 2021-01-08 19:15:34 +1100 | [diff] [blame] | 269 | bool MountManager::ResolvePath(const std::string& path, |
| 270 | std::string* real_path) { |
| 271 | return platform_->GetRealPath(path, real_path); |
| 272 | } |
| 273 | |
| 274 | MountPoint* MountManager::FindMountBySource(const std::string& source) { |
Sergei Datsenko | 0ba1203 | 2021-01-07 08:51:14 +1100 | [diff] [blame] | 275 | const auto it = mount_states_.find(source); |
| 276 | if (it == mount_states_.end()) |
| 277 | return nullptr; |
Sergei Datsenko | 7e7c764 | 2021-01-08 19:15:34 +1100 | [diff] [blame] | 278 | return it->second.get(); |
Sergei Datsenko | 0ba1203 | 2021-01-07 08:51:14 +1100 | [diff] [blame] | 279 | } |
| 280 | |
Sergei Datsenko | 7e7c764 | 2021-01-08 19:15:34 +1100 | [diff] [blame] | 281 | MountPoint* MountManager::FindMountByMountPath(const base::FilePath& path) { |
| 282 | for (auto& entry : mount_states_) { |
| 283 | if (entry.second->path() == path) |
| 284 | return entry.second.get(); |
Anand K Mistry | e9a60fb | 2019-11-07 16:41:03 +1100 | [diff] [blame] | 285 | } |
Sergei Datsenko | 7e7c764 | 2021-01-08 19:15:34 +1100 | [diff] [blame] | 286 | return nullptr; |
Ben Chan | 8dcede8 | 2011-07-25 20:56:13 -0700 | [diff] [blame] | 287 | } |
| 288 | |
Sergei Datsenko | 7e7c764 | 2021-01-08 19:15:34 +1100 | [diff] [blame] | 289 | bool MountManager::RemoveMount(MountPoint* mount_point) { |
François Degros | a9d3905 | 2020-02-20 12:20:00 +1100 | [diff] [blame] | 290 | for (auto it = mount_states_.begin(); it != mount_states_.end(); ++it) { |
Sergei Datsenko | 7e7c764 | 2021-01-08 19:15:34 +1100 | [diff] [blame] | 291 | if (it->second.get() == mount_point) { |
François Degros | a9d3905 | 2020-02-20 12:20:00 +1100 | [diff] [blame] | 292 | mount_states_.erase(it); |
Ben Chan | 8dcede8 | 2011-07-25 20:56:13 -0700 | [diff] [blame] | 293 | return true; |
| 294 | } |
| 295 | } |
| 296 | return false; |
| 297 | } |
| 298 | |
Sergei Datsenko | 7e7c764 | 2021-01-08 19:15:34 +1100 | [diff] [blame] | 299 | MountErrorType MountManager::CreateMountPathForSource( |
| 300 | const std::string& source, |
| 301 | const std::string& label, |
| 302 | base::FilePath* mount_path) { |
| 303 | base::FilePath actual_mount_path = *mount_path; |
| 304 | if (actual_mount_path.empty()) { |
| 305 | actual_mount_path = base::FilePath(SuggestMountPath(source)); |
| 306 | if (!label.empty()) { |
| 307 | // Replace the basename(|actual_mount_path|) with |label|. |
| 308 | actual_mount_path = actual_mount_path.DirName().Append(label); |
| 309 | } |
| 310 | } |
| 311 | |
| 312 | if (!IsValidMountPath(base::FilePath(actual_mount_path))) { |
| 313 | LOG(ERROR) << "Mount path " << quote(actual_mount_path) << " is invalid"; |
| 314 | return MOUNT_ERROR_INVALID_PATH; |
| 315 | } |
| 316 | |
| 317 | bool mount_path_created; |
| 318 | if (!mount_path->empty()) { |
| 319 | mount_path_created = |
| 320 | !IsMountPathReserved(actual_mount_path) && |
| 321 | platform_->CreateOrReuseEmptyDirectory(actual_mount_path.value()); |
| 322 | } else { |
| 323 | std::unordered_set<std::string> reserved_paths; |
| 324 | for (const auto& entry : reserved_mount_paths_) { |
| 325 | reserved_paths.insert(entry.first.value()); |
| 326 | } |
| 327 | std::string path = actual_mount_path.value(); |
| 328 | mount_path_created = platform_->CreateOrReuseEmptyDirectoryWithFallback( |
| 329 | &path, kMaxNumMountTrials, reserved_paths); |
| 330 | if (mount_path_created) |
| 331 | actual_mount_path = base::FilePath(path); |
| 332 | } |
| 333 | if (!mount_path_created) { |
| 334 | LOG(ERROR) << "Cannot create directory " << quote(actual_mount_path) |
| 335 | << " to mount " << quote(source); |
| 336 | return MOUNT_ERROR_DIRECTORY_CREATION_FAILED; |
| 337 | } |
| 338 | |
| 339 | *mount_path = actual_mount_path; |
| 340 | return MOUNT_ERROR_NONE; |
| 341 | } |
| 342 | |
| 343 | bool MountManager::IsMountPathReserved(const base::FilePath& mount_path) const { |
Qijiang Fan | 5243904 | 2020-06-17 15:34:38 +0900 | [diff] [blame] | 344 | return base::Contains(reserved_mount_paths_, mount_path); |
Ben Chan | f869288 | 2011-08-21 10:15:30 -0700 | [diff] [blame] | 345 | } |
| 346 | |
Ben Chan | 632c9f8 | 2011-10-11 12:22:16 -0700 | [diff] [blame] | 347 | MountErrorType MountManager::GetMountErrorOfReservedMountPath( |
Sergei Datsenko | 7e7c764 | 2021-01-08 19:15:34 +1100 | [diff] [blame] | 348 | const base::FilePath& mount_path) const { |
François Degros | a9d3905 | 2020-02-20 12:20:00 +1100 | [diff] [blame] | 349 | const auto it = reserved_mount_paths_.find(mount_path); |
| 350 | return it != reserved_mount_paths_.end() ? it->second : MOUNT_ERROR_NONE; |
Ben Chan | 632c9f8 | 2011-10-11 12:22:16 -0700 | [diff] [blame] | 351 | } |
| 352 | |
Sergei Datsenko | 7e7c764 | 2021-01-08 19:15:34 +1100 | [diff] [blame] | 353 | void MountManager::ReserveMountPath(base::FilePath mount_path, |
Ben Chan | 632c9f8 | 2011-10-11 12:22:16 -0700 | [diff] [blame] | 354 | MountErrorType error_type) { |
Sergei Datsenko | 7e7c764 | 2021-01-08 19:15:34 +1100 | [diff] [blame] | 355 | reserved_mount_paths_.insert({std::move(mount_path), error_type}); |
Ben Chan | f869288 | 2011-08-21 10:15:30 -0700 | [diff] [blame] | 356 | } |
| 357 | |
Sergei Datsenko | 7e7c764 | 2021-01-08 19:15:34 +1100 | [diff] [blame] | 358 | void MountManager::UnreserveMountPath(const base::FilePath& mount_path) { |
Ben Chan | f869288 | 2011-08-21 10:15:30 -0700 | [diff] [blame] | 359 | reserved_mount_paths_.erase(mount_path); |
| 360 | } |
| 361 | |
Ben Chan | 213c6d9 | 2019-04-10 16:21:52 -0700 | [diff] [blame] | 362 | std::vector<MountEntry> MountManager::GetMountEntries() const { |
| 363 | std::vector<MountEntry> mount_entries; |
François Degros | a9d3905 | 2020-02-20 12:20:00 +1100 | [diff] [blame] | 364 | mount_entries.reserve(mount_states_.size()); |
Tatsuhisa Yamaguchi | 5a6a303 | 2016-08-19 20:03:54 +0900 | [diff] [blame] | 365 | for (const auto& entry : mount_states_) { |
Ben Chan | 213c6d9 | 2019-04-10 16:21:52 -0700 | [diff] [blame] | 366 | const std::string& source_path = entry.first; |
Sergei Datsenko | 7e7c764 | 2021-01-08 19:15:34 +1100 | [diff] [blame] | 367 | const MountPoint& mount_point = *entry.second; |
| 368 | |
| 369 | mount_entries.push_back( |
| 370 | {GetMountErrorOfReservedMountPath(mount_point.path()), source_path, |
| 371 | GetMountSourceType(), mount_point.path().value(), |
| 372 | mount_point.is_read_only()}); |
Ben Chan | 8fb742b | 2014-04-28 23:46:57 -0700 | [diff] [blame] | 373 | } |
Ben Chan | 7dfb810 | 2017-10-17 15:47:37 -0700 | [diff] [blame] | 374 | return mount_entries; |
Ben Chan | 8fb742b | 2014-04-28 23:46:57 -0700 | [diff] [blame] | 375 | } |
| 376 | |
Ben Chan | f869288 | 2011-08-21 10:15:30 -0700 | [diff] [blame] | 377 | bool MountManager::ShouldReserveMountPathOnError( |
| 378 | MountErrorType error_type) const { |
| 379 | return false; |
| 380 | } |
| 381 | |
Sergei Datsenko | 7e7c764 | 2021-01-08 19:15:34 +1100 | [diff] [blame] | 382 | bool MountManager::IsPathImmediateChildOfParent(const base::FilePath& path, |
| 383 | const base::FilePath& parent) { |
Ben Chan | 213c6d9 | 2019-04-10 16:21:52 -0700 | [diff] [blame] | 384 | std::vector<std::string> path_components, parent_components; |
Anand K Mistry | 09f2db1 | 2019-11-07 17:06:56 +1100 | [diff] [blame] | 385 | path.StripTrailingSeparators().GetComponents(&path_components); |
| 386 | parent.StripTrailingSeparators().GetComponents(&parent_components); |
Ben Chan | 8dcede8 | 2011-07-25 20:56:13 -0700 | [diff] [blame] | 387 | if (path_components.size() != parent_components.size() + 1) |
| 388 | return false; |
| 389 | |
Ben Chan | 213c6d9 | 2019-04-10 16:21:52 -0700 | [diff] [blame] | 390 | if (path_components.back() == base::FilePath::kCurrentDirectory || |
| 391 | path_components.back() == base::FilePath::kParentDirectory) { |
Ben Chan | 8698d23 | 2018-06-04 21:44:30 -0700 | [diff] [blame] | 392 | return false; |
| 393 | } |
| 394 | |
Ben Chan | 8dcede8 | 2011-07-25 20:56:13 -0700 | [diff] [blame] | 395 | return std::equal(parent_components.begin(), parent_components.end(), |
| 396 | path_components.begin()); |
| 397 | } |
| 398 | |
Anand K Mistry | 09f2db1 | 2019-11-07 17:06:56 +1100 | [diff] [blame] | 399 | bool MountManager::IsValidMountPath(const base::FilePath& mount_path) const { |
Ben Chan | adc5d00 | 2014-03-12 15:02:26 -0700 | [diff] [blame] | 400 | return IsPathImmediateChildOfParent(mount_path, mount_root_); |
| 401 | } |
| 402 | |
Ben Chan | 8dcede8 | 2011-07-25 20:56:13 -0700 | [diff] [blame] | 403 | } // namespace cros_disks |