| OLD | NEW |
| (Empty) |
| 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 | |
| 5 #include "chrome/browser/chromeos/disks/disk_mount_manager.h" | |
| 6 | |
| 7 #include <sys/statvfs.h> | |
| 8 | |
| 9 #include <map> | |
| 10 #include <set> | |
| 11 | |
| 12 #include "base/bind.h" | |
| 13 #include "base/memory/weak_ptr.h" | |
| 14 #include "base/observer_list.h" | |
| 15 #include "base/string_util.h" | |
| 16 #include "chromeos/dbus/dbus_thread_manager.h" | |
| 17 #include "content/public/browser/browser_thread.h" | |
| 18 | |
| 19 using content::BrowserThread; | |
| 20 | |
| 21 namespace chromeos { | |
| 22 namespace disks { | |
| 23 | |
| 24 namespace { | |
| 25 | |
| 26 const char kDeviceNotFound[] = "Device could not be found"; | |
| 27 | |
| 28 DiskMountManager* g_disk_mount_manager = NULL; | |
| 29 | |
| 30 // The DiskMountManager implementation. | |
| 31 class DiskMountManagerImpl : public DiskMountManager { | |
| 32 public: | |
| 33 DiskMountManagerImpl() : weak_ptr_factory_(this) { | |
| 34 DBusThreadManager* dbus_thread_manager = DBusThreadManager::Get(); | |
| 35 DCHECK(dbus_thread_manager); | |
| 36 cros_disks_client_ = dbus_thread_manager->GetCrosDisksClient(); | |
| 37 DCHECK(cros_disks_client_); | |
| 38 | |
| 39 cros_disks_client_->SetUpConnections( | |
| 40 base::Bind(&DiskMountManagerImpl::OnMountEvent, | |
| 41 weak_ptr_factory_.GetWeakPtr()), | |
| 42 base::Bind(&DiskMountManagerImpl::OnMountCompleted, | |
| 43 weak_ptr_factory_.GetWeakPtr())); | |
| 44 } | |
| 45 | |
| 46 virtual ~DiskMountManagerImpl() { | |
| 47 } | |
| 48 | |
| 49 // DiskMountManager override. | |
| 50 virtual void AddObserver(Observer* observer) OVERRIDE { | |
| 51 observers_.AddObserver(observer); | |
| 52 } | |
| 53 | |
| 54 // DiskMountManager override. | |
| 55 virtual void RemoveObserver(Observer* observer) OVERRIDE { | |
| 56 observers_.RemoveObserver(observer); | |
| 57 } | |
| 58 | |
| 59 // DiskMountManager override. | |
| 60 virtual void MountPath(const std::string& source_path, | |
| 61 const std::string& source_format, | |
| 62 const std::string& mount_label, | |
| 63 MountType type) OVERRIDE { | |
| 64 // Hidden and non-existent devices should not be mounted. | |
| 65 if (type == MOUNT_TYPE_DEVICE) { | |
| 66 DiskMap::const_iterator it = disks_.find(source_path); | |
| 67 if (it == disks_.end() || it->second->is_hidden()) { | |
| 68 OnMountCompleted(MOUNT_ERROR_INTERNAL, source_path, type, ""); | |
| 69 return; | |
| 70 } | |
| 71 } | |
| 72 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 73 cros_disks_client_->Mount( | |
| 74 source_path, | |
| 75 source_format, | |
| 76 mount_label, | |
| 77 type, | |
| 78 // When succeeds, OnMountCompleted will be called by | |
| 79 // "MountCompleted" signal instead. | |
| 80 base::Bind(&base::DoNothing), | |
| 81 base::Bind(&DiskMountManagerImpl::OnMountCompleted, | |
| 82 weak_ptr_factory_.GetWeakPtr(), | |
| 83 MOUNT_ERROR_INTERNAL, | |
| 84 source_path, | |
| 85 type, | |
| 86 "")); | |
| 87 } | |
| 88 | |
| 89 // DiskMountManager override. | |
| 90 virtual void UnmountPath(const std::string& mount_path) OVERRIDE { | |
| 91 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 92 cros_disks_client_->Unmount(mount_path, | |
| 93 base::Bind(&DiskMountManagerImpl::OnUnmountPath, | |
| 94 weak_ptr_factory_.GetWeakPtr()), | |
| 95 base::Bind(&base::DoNothing)); | |
| 96 } | |
| 97 | |
| 98 // DiskMountManager override. | |
| 99 virtual void GetSizeStatsOnFileThread(const std::string& mount_path, | |
| 100 size_t* total_size_kb, | |
| 101 size_t* remaining_size_kb) OVERRIDE { | |
| 102 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | |
| 103 | |
| 104 uint64_t total_size_in_bytes = 0; | |
| 105 uint64_t remaining_size_in_bytes = 0; | |
| 106 | |
| 107 struct statvfs stat = {}; // Zero-clear | |
| 108 if (statvfs(mount_path.c_str(), &stat) == 0) { | |
| 109 total_size_in_bytes = | |
| 110 static_cast<uint64_t>(stat.f_blocks) * stat.f_frsize; | |
| 111 remaining_size_in_bytes = | |
| 112 static_cast<uint64_t>(stat.f_bfree) * stat.f_frsize; | |
| 113 } | |
| 114 *total_size_kb = static_cast<size_t>(total_size_in_bytes / 1024); | |
| 115 *remaining_size_kb = static_cast<size_t>(remaining_size_in_bytes / 1024); | |
| 116 } | |
| 117 | |
| 118 // DiskMountManager override. | |
| 119 virtual void FormatUnmountedDevice(const std::string& file_path) OVERRIDE { | |
| 120 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 121 for (DiskMountManager::DiskMap::iterator it = disks_.begin(); | |
| 122 it != disks_.end(); ++it) { | |
| 123 if (it->second->file_path() == file_path && | |
| 124 !it->second->mount_path().empty()) { | |
| 125 LOG(ERROR) << "Device is still mounted: " << file_path; | |
| 126 OnFormatDevice(file_path, false); | |
| 127 return; | |
| 128 } | |
| 129 } | |
| 130 const char kFormatVFAT[] = "vfat"; | |
| 131 cros_disks_client_->FormatDevice( | |
| 132 file_path, | |
| 133 kFormatVFAT, | |
| 134 base::Bind(&DiskMountManagerImpl::OnFormatDevice, | |
| 135 weak_ptr_factory_.GetWeakPtr()), | |
| 136 base::Bind(&DiskMountManagerImpl::OnFormatDevice, | |
| 137 weak_ptr_factory_.GetWeakPtr(), | |
| 138 file_path, | |
| 139 false)); | |
| 140 } | |
| 141 | |
| 142 // DiskMountManager override. | |
| 143 virtual void FormatMountedDevice(const std::string& mount_path) OVERRIDE { | |
| 144 Disk* disk = NULL; | |
| 145 for (DiskMountManager::DiskMap::iterator it = disks_.begin(); | |
| 146 it != disks_.end(); ++it) { | |
| 147 if (it->second->mount_path() == mount_path) { | |
| 148 disk = it->second; | |
| 149 break; | |
| 150 } | |
| 151 } | |
| 152 if (!disk) { | |
| 153 LOG(ERROR) << "Device with this mount path not found: " << mount_path; | |
| 154 OnFormatDevice(mount_path, false); | |
| 155 return; | |
| 156 } | |
| 157 if (formatting_pending_.find(disk->device_path()) != | |
| 158 formatting_pending_.end()) { | |
| 159 LOG(ERROR) << "Formatting is already pending: " << mount_path; | |
| 160 OnFormatDevice(mount_path, false); | |
| 161 return; | |
| 162 } | |
| 163 // Formatting process continues, after unmounting. | |
| 164 formatting_pending_[disk->device_path()] = disk->file_path(); | |
| 165 UnmountPath(disk->mount_path()); | |
| 166 } | |
| 167 | |
| 168 // DiskMountManager override. | |
| 169 virtual void UnmountDeviceRecursive( | |
| 170 const std::string& device_path, | |
| 171 UnmountDeviceRecursiveCallbackType callback, | |
| 172 void* user_data) OVERRIDE { | |
| 173 bool success = true; | |
| 174 std::string error_message; | |
| 175 std::vector<std::string> devices_to_unmount; | |
| 176 | |
| 177 // Get list of all devices to unmount. | |
| 178 int device_path_len = device_path.length(); | |
| 179 for (DiskMap::iterator it = disks_.begin(); it != disks_.end(); ++it) { | |
| 180 if (!it->second->mount_path().empty() && | |
| 181 strncmp(device_path.c_str(), it->second->device_path().c_str(), | |
| 182 device_path_len) == 0) { | |
| 183 devices_to_unmount.push_back(it->second->mount_path()); | |
| 184 } | |
| 185 } | |
| 186 // We should detect at least original device. | |
| 187 if (devices_to_unmount.empty()) { | |
| 188 if (disks_.find(device_path) == disks_.end()) { | |
| 189 success = false; | |
| 190 error_message = kDeviceNotFound; | |
| 191 } else { | |
| 192 // Nothing to unmount. | |
| 193 callback(user_data, true); | |
| 194 return; | |
| 195 } | |
| 196 } | |
| 197 if (success) { | |
| 198 // We will send the same callback data object to all Unmount calls and use | |
| 199 // it to syncronize callbacks. | |
| 200 UnmountDeviceRecursiveCallbackData* cb_data = | |
| 201 new UnmountDeviceRecursiveCallbackData(user_data, callback, | |
| 202 devices_to_unmount.size()); | |
| 203 for (size_t i = 0; i < devices_to_unmount.size(); ++i) { | |
| 204 cros_disks_client_->Unmount( | |
| 205 devices_to_unmount[i], | |
| 206 base::Bind(&DiskMountManagerImpl::OnUnmountDeviceRecursive, | |
| 207 weak_ptr_factory_.GetWeakPtr(), cb_data, true), | |
| 208 base::Bind(&DiskMountManagerImpl::OnUnmountDeviceRecursive, | |
| 209 weak_ptr_factory_.GetWeakPtr(), | |
| 210 cb_data, | |
| 211 false, | |
| 212 devices_to_unmount[i])); | |
| 213 } | |
| 214 } else { | |
| 215 LOG(WARNING) << "Unmount recursive request failed for device " | |
| 216 << device_path << ", with error: " << error_message; | |
| 217 callback(user_data, false); | |
| 218 } | |
| 219 } | |
| 220 | |
| 221 // DiskMountManager override. | |
| 222 virtual void RequestMountInfoRefresh() OVERRIDE { | |
| 223 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 224 cros_disks_client_->EnumerateAutoMountableDevices( | |
| 225 base::Bind(&DiskMountManagerImpl::OnRequestMountInfo, | |
| 226 weak_ptr_factory_.GetWeakPtr()), | |
| 227 base::Bind(&base::DoNothing)); | |
| 228 } | |
| 229 | |
| 230 // DiskMountManager override. | |
| 231 const DiskMap& disks() const OVERRIDE { return disks_; } | |
| 232 | |
| 233 // DiskMountManager override. | |
| 234 virtual const Disk* FindDiskBySourcePath(const std::string& source_path) | |
| 235 const OVERRIDE { | |
| 236 DiskMap::const_iterator disk_it = disks_.find(source_path); | |
| 237 return disk_it == disks_.end() ? NULL : disk_it->second; | |
| 238 } | |
| 239 | |
| 240 // DiskMountManager override. | |
| 241 const MountPointMap& mount_points() const OVERRIDE { return mount_points_; } | |
| 242 | |
| 243 private: | |
| 244 struct UnmountDeviceRecursiveCallbackData { | |
| 245 void* user_data; | |
| 246 UnmountDeviceRecursiveCallbackType callback; | |
| 247 size_t pending_callbacks_count; | |
| 248 | |
| 249 UnmountDeviceRecursiveCallbackData(void* ud, | |
| 250 UnmountDeviceRecursiveCallbackType cb, | |
| 251 int count) | |
| 252 : user_data(ud), | |
| 253 callback(cb), | |
| 254 pending_callbacks_count(count) { | |
| 255 } | |
| 256 }; | |
| 257 | |
| 258 // Callback for UnmountDeviceRecursive. | |
| 259 void OnUnmountDeviceRecursive(UnmountDeviceRecursiveCallbackData* cb_data, | |
| 260 bool success, | |
| 261 const std::string& mount_path) { | |
| 262 if (success) { | |
| 263 // Do standard processing for Unmount event. | |
| 264 OnUnmountPath(mount_path); | |
| 265 LOG(INFO) << mount_path << " unmounted."; | |
| 266 } | |
| 267 // This is safe as long as all callbacks are called on the same thread as | |
| 268 // UnmountDeviceRecursive. | |
| 269 cb_data->pending_callbacks_count--; | |
| 270 | |
| 271 if (cb_data->pending_callbacks_count == 0) { | |
| 272 cb_data->callback(cb_data->user_data, success); | |
| 273 delete cb_data; | |
| 274 } | |
| 275 } | |
| 276 | |
| 277 // Callback to handle MountCompleted signal and Mount method call failure. | |
| 278 void OnMountCompleted(MountError error_code, | |
| 279 const std::string& source_path, | |
| 280 MountType mount_type, | |
| 281 const std::string& mount_path) { | |
| 282 MountCondition mount_condition = MOUNT_CONDITION_NONE; | |
| 283 if (mount_type == MOUNT_TYPE_DEVICE) { | |
| 284 if (error_code == MOUNT_ERROR_UNKNOWN_FILESYSTEM) { | |
| 285 mount_condition = MOUNT_CONDITION_UNKNOWN_FILESYSTEM; | |
| 286 } | |
| 287 if (error_code == MOUNT_ERROR_UNSUPPORTED_FILESYSTEM) { | |
| 288 mount_condition = MOUNT_CONDITION_UNSUPPORTED_FILESYSTEM; | |
| 289 } | |
| 290 } | |
| 291 const MountPointInfo mount_info(source_path, mount_path, mount_type, | |
| 292 mount_condition); | |
| 293 | |
| 294 NotifyMountCompleted(MOUNTING, error_code, mount_info); | |
| 295 | |
| 296 // If the device is corrupted but it's still possible to format it, it will | |
| 297 // be fake mounted. | |
| 298 if ((error_code == MOUNT_ERROR_NONE || mount_info.mount_condition) && | |
| 299 mount_points_.find(mount_info.mount_path) == mount_points_.end()) { | |
| 300 mount_points_.insert(MountPointMap::value_type(mount_info.mount_path, | |
| 301 mount_info)); | |
| 302 } | |
| 303 if ((error_code == MOUNT_ERROR_NONE || mount_info.mount_condition) && | |
| 304 mount_info.mount_type == MOUNT_TYPE_DEVICE && | |
| 305 !mount_info.source_path.empty() && | |
| 306 !mount_info.mount_path.empty()) { | |
| 307 DiskMap::iterator iter = disks_.find(mount_info.source_path); | |
| 308 if (iter == disks_.end()) { | |
| 309 // disk might have been removed by now? | |
| 310 return; | |
| 311 } | |
| 312 Disk* disk = iter->second; | |
| 313 DCHECK(disk); | |
| 314 disk->set_mount_path(mount_info.mount_path); | |
| 315 NotifyDiskStatusUpdate(MOUNT_DISK_MOUNTED, disk); | |
| 316 } | |
| 317 } | |
| 318 | |
| 319 // Callback for UnmountPath. | |
| 320 void OnUnmountPath(const std::string& mount_path) { | |
| 321 MountPointMap::iterator mount_points_it = mount_points_.find(mount_path); | |
| 322 if (mount_points_it == mount_points_.end()) | |
| 323 return; | |
| 324 // TODO(tbarzic): Add separate, PathUnmounted event to Observer. | |
| 325 NotifyMountCompleted( | |
| 326 UNMOUNTING, MOUNT_ERROR_NONE, | |
| 327 MountPointInfo(mount_points_it->second.source_path, | |
| 328 mount_points_it->second.mount_path, | |
| 329 mount_points_it->second.mount_type, | |
| 330 mount_points_it->second.mount_condition)); | |
| 331 std::string path(mount_points_it->second.source_path); | |
| 332 mount_points_.erase(mount_points_it); | |
| 333 DiskMap::iterator iter = disks_.find(path); | |
| 334 if (iter == disks_.end()) { | |
| 335 // disk might have been removed by now. | |
| 336 return; | |
| 337 } | |
| 338 Disk* disk = iter->second; | |
| 339 DCHECK(disk); | |
| 340 disk->clear_mount_path(); | |
| 341 // Check if there is a formatting scheduled. | |
| 342 PathMap::iterator it = formatting_pending_.find(disk->device_path()); | |
| 343 if (it != formatting_pending_.end()) { | |
| 344 // Copy the string before it gets erased. | |
| 345 const std::string file_path = it->second; | |
| 346 formatting_pending_.erase(it); | |
| 347 FormatUnmountedDevice(file_path); | |
| 348 } | |
| 349 } | |
| 350 | |
| 351 // Callback for FormatDevice. | |
| 352 void OnFormatDevice(const std::string& device_path, bool success) { | |
| 353 if (success) { | |
| 354 NotifyDeviceStatusUpdate(MOUNT_FORMATTING_STARTED, device_path); | |
| 355 } else { | |
| 356 NotifyDeviceStatusUpdate(MOUNT_FORMATTING_STARTED, | |
| 357 std::string("!") + device_path); | |
| 358 LOG(WARNING) << "Format request failed for device " << device_path; | |
| 359 } | |
| 360 } | |
| 361 | |
| 362 // Callbcak for GetDeviceProperties. | |
| 363 void OnGetDeviceProperties(const DiskInfo& disk_info) { | |
| 364 // TODO(zelidrag): Find a better way to filter these out before we | |
| 365 // fetch the properties: | |
| 366 // Ignore disks coming from the device we booted the system from. | |
| 367 if (disk_info.on_boot_device()) | |
| 368 return; | |
| 369 | |
| 370 LOG(WARNING) << "Found disk " << disk_info.device_path(); | |
| 371 // Delete previous disk info for this path: | |
| 372 bool is_new = true; | |
| 373 DiskMap::iterator iter = disks_.find(disk_info.device_path()); | |
| 374 if (iter != disks_.end()) { | |
| 375 delete iter->second; | |
| 376 disks_.erase(iter); | |
| 377 is_new = false; | |
| 378 } | |
| 379 Disk* disk = new Disk(disk_info.device_path(), | |
| 380 disk_info.mount_path(), | |
| 381 disk_info.system_path(), | |
| 382 disk_info.file_path(), | |
| 383 disk_info.label(), | |
| 384 disk_info.drive_label(), | |
| 385 disk_info.uuid(), | |
| 386 FindSystemPathPrefix(disk_info.system_path()), | |
| 387 disk_info.device_type(), | |
| 388 disk_info.total_size_in_bytes(), | |
| 389 disk_info.is_drive(), | |
| 390 disk_info.is_read_only(), | |
| 391 disk_info.has_media(), | |
| 392 disk_info.on_boot_device(), | |
| 393 disk_info.is_hidden()); | |
| 394 disks_.insert(std::make_pair(disk_info.device_path(), disk)); | |
| 395 NotifyDiskStatusUpdate(is_new ? MOUNT_DISK_ADDED : MOUNT_DISK_CHANGED, | |
| 396 disk); | |
| 397 } | |
| 398 | |
| 399 // Callbcak for RequestMountInfo. | |
| 400 void OnRequestMountInfo(const std::vector<std::string>& devices) { | |
| 401 std::set<std::string> current_device_set; | |
| 402 if (!devices.empty()) { | |
| 403 // Initiate properties fetch for all removable disks, | |
| 404 for (size_t i = 0; i < devices.size(); i++) { | |
| 405 current_device_set.insert(devices[i]); | |
| 406 // Initiate disk property retrieval for each relevant device path. | |
| 407 cros_disks_client_->GetDeviceProperties( | |
| 408 devices[i], | |
| 409 base::Bind(&DiskMountManagerImpl::OnGetDeviceProperties, | |
| 410 weak_ptr_factory_.GetWeakPtr()), | |
| 411 base::Bind(&base::DoNothing)); | |
| 412 } | |
| 413 } | |
| 414 // Search and remove disks that are no longer present. | |
| 415 for (DiskMap::iterator iter = disks_.begin(); iter != disks_.end(); ) { | |
| 416 if (current_device_set.find(iter->first) == current_device_set.end()) { | |
| 417 Disk* disk = iter->second; | |
| 418 NotifyDiskStatusUpdate(MOUNT_DISK_REMOVED, disk); | |
| 419 delete iter->second; | |
| 420 disks_.erase(iter++); | |
| 421 } else { | |
| 422 ++iter; | |
| 423 } | |
| 424 } | |
| 425 } | |
| 426 | |
| 427 // Callback to handle mount event signals. | |
| 428 void OnMountEvent(MountEventType event, const std::string& device_path_arg) { | |
| 429 // Take a copy of the argument so we can modify it below. | |
| 430 std::string device_path = device_path_arg; | |
| 431 DiskMountManagerEventType type = MOUNT_DEVICE_ADDED; | |
| 432 switch (event) { | |
| 433 case DISK_ADDED: { | |
| 434 cros_disks_client_->GetDeviceProperties( | |
| 435 device_path, | |
| 436 base::Bind(&DiskMountManagerImpl::OnGetDeviceProperties, | |
| 437 weak_ptr_factory_.GetWeakPtr()), | |
| 438 base::Bind(&base::DoNothing)); | |
| 439 return; | |
| 440 } | |
| 441 case DISK_REMOVED: { | |
| 442 // Search and remove disks that are no longer present. | |
| 443 DiskMountManager::DiskMap::iterator iter = disks_.find(device_path); | |
| 444 if (iter != disks_.end()) { | |
| 445 Disk* disk = iter->second; | |
| 446 NotifyDiskStatusUpdate(MOUNT_DISK_REMOVED, disk); | |
| 447 delete iter->second; | |
| 448 disks_.erase(iter); | |
| 449 } | |
| 450 return; | |
| 451 } | |
| 452 case DEVICE_ADDED: { | |
| 453 type = MOUNT_DEVICE_ADDED; | |
| 454 system_path_prefixes_.insert(device_path); | |
| 455 break; | |
| 456 } | |
| 457 case DEVICE_REMOVED: { | |
| 458 type = MOUNT_DEVICE_REMOVED; | |
| 459 system_path_prefixes_.erase(device_path); | |
| 460 break; | |
| 461 } | |
| 462 case DEVICE_SCANNED: { | |
| 463 type = MOUNT_DEVICE_SCANNED; | |
| 464 break; | |
| 465 } | |
| 466 case FORMATTING_FINISHED: { | |
| 467 // FORMATTING_FINISHED actually returns file path instead of device | |
| 468 // path. | |
| 469 device_path = FilePathToDevicePath(device_path); | |
| 470 if (device_path.empty()) { | |
| 471 LOG(ERROR) << "Error while handling disks metadata. Cannot find " | |
| 472 << "device that is being formatted."; | |
| 473 return; | |
| 474 } | |
| 475 type = MOUNT_FORMATTING_FINISHED; | |
| 476 break; | |
| 477 } | |
| 478 default: { | |
| 479 LOG(ERROR) << "Unknown event: " << event; | |
| 480 return; | |
| 481 } | |
| 482 } | |
| 483 NotifyDeviceStatusUpdate(type, device_path); | |
| 484 } | |
| 485 | |
| 486 // Notifies all observers about disk status update. | |
| 487 void NotifyDiskStatusUpdate(DiskMountManagerEventType event, | |
| 488 const Disk* disk) { | |
| 489 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 490 FOR_EACH_OBSERVER(Observer, observers_, DiskChanged(event, disk)); | |
| 491 } | |
| 492 | |
| 493 // Notifies all observers about device status update. | |
| 494 void NotifyDeviceStatusUpdate(DiskMountManagerEventType event, | |
| 495 const std::string& device_path) { | |
| 496 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 497 FOR_EACH_OBSERVER(Observer, observers_, DeviceChanged(event, device_path)); | |
| 498 } | |
| 499 | |
| 500 // Notifies all observers about mount completion. | |
| 501 void NotifyMountCompleted(MountEvent event_type, | |
| 502 MountError error_code, | |
| 503 const MountPointInfo& mount_info) { | |
| 504 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 505 FOR_EACH_OBSERVER(Observer, observers_, | |
| 506 MountCompleted(event_type, error_code, mount_info)); | |
| 507 } | |
| 508 | |
| 509 // Converts file path to device path. | |
| 510 std::string FilePathToDevicePath(const std::string& file_path) { | |
| 511 // TODO(hashimoto): Refactor error handling code like here. | |
| 512 // Appending "!" is not the best way to indicate error. This kind of trick | |
| 513 // also makes it difficult to simplify the code paths. crosbug.com/22972 | |
| 514 const int failed = StartsWithASCII(file_path, "!", true); | |
| 515 for (DiskMountManager::DiskMap::iterator it = disks_.begin(); | |
| 516 it != disks_.end(); ++it) { | |
| 517 // Skip the leading '!' on the failure case. | |
| 518 if (it->second->file_path() == file_path.substr(failed)) { | |
| 519 if (failed) | |
| 520 return std::string("!") + it->second->device_path(); | |
| 521 else | |
| 522 return it->second->device_path(); | |
| 523 } | |
| 524 } | |
| 525 return ""; | |
| 526 } | |
| 527 | |
| 528 // Finds system path prefix from |system_path|. | |
| 529 const std::string& FindSystemPathPrefix(const std::string& system_path) { | |
| 530 if (system_path.empty()) | |
| 531 return EmptyString(); | |
| 532 for (SystemPathPrefixSet::const_iterator it = system_path_prefixes_.begin(); | |
| 533 it != system_path_prefixes_.end(); | |
| 534 ++it) { | |
| 535 const std::string& prefix = *it; | |
| 536 if (StartsWithASCII(system_path, prefix, true)) | |
| 537 return prefix; | |
| 538 } | |
| 539 return EmptyString(); | |
| 540 } | |
| 541 | |
| 542 // Mount event change observers. | |
| 543 ObserverList<Observer> observers_; | |
| 544 | |
| 545 CrosDisksClient* cros_disks_client_; | |
| 546 | |
| 547 // The list of disks found. | |
| 548 DiskMountManager::DiskMap disks_; | |
| 549 | |
| 550 DiskMountManager::MountPointMap mount_points_; | |
| 551 | |
| 552 typedef std::set<std::string> SystemPathPrefixSet; | |
| 553 SystemPathPrefixSet system_path_prefixes_; | |
| 554 | |
| 555 // A map from device path (e.g. /sys/devices/pci0000:00/.../sdb/sdb1)) to file | |
| 556 // path (e.g. /dev/sdb). | |
| 557 // Devices in this map are supposed to be formatted, but are currently waiting | |
| 558 // to be unmounted. When device is in this map, the formatting process HAVEN'T | |
| 559 // started yet. | |
| 560 typedef std::map<std::string, std::string> PathMap; | |
| 561 PathMap formatting_pending_; | |
| 562 | |
| 563 base::WeakPtrFactory<DiskMountManagerImpl> weak_ptr_factory_; | |
| 564 | |
| 565 DISALLOW_COPY_AND_ASSIGN(DiskMountManagerImpl); | |
| 566 }; | |
| 567 | |
| 568 } // namespace | |
| 569 | |
| 570 DiskMountManager::Disk::Disk(const std::string& device_path, | |
| 571 const std::string& mount_path, | |
| 572 const std::string& system_path, | |
| 573 const std::string& file_path, | |
| 574 const std::string& device_label, | |
| 575 const std::string& drive_label, | |
| 576 const std::string& fs_uuid, | |
| 577 const std::string& system_path_prefix, | |
| 578 DeviceType device_type, | |
| 579 uint64 total_size_in_bytes, | |
| 580 bool is_parent, | |
| 581 bool is_read_only, | |
| 582 bool has_media, | |
| 583 bool on_boot_device, | |
| 584 bool is_hidden) | |
| 585 : device_path_(device_path), | |
| 586 mount_path_(mount_path), | |
| 587 system_path_(system_path), | |
| 588 file_path_(file_path), | |
| 589 device_label_(device_label), | |
| 590 drive_label_(drive_label), | |
| 591 fs_uuid_(fs_uuid), | |
| 592 system_path_prefix_(system_path_prefix), | |
| 593 device_type_(device_type), | |
| 594 total_size_in_bytes_(total_size_in_bytes), | |
| 595 is_parent_(is_parent), | |
| 596 is_read_only_(is_read_only), | |
| 597 has_media_(has_media), | |
| 598 on_boot_device_(on_boot_device), | |
| 599 is_hidden_(is_hidden) { | |
| 600 } | |
| 601 | |
| 602 DiskMountManager::Disk::~Disk() {} | |
| 603 | |
| 604 // static | |
| 605 std::string DiskMountManager::MountTypeToString(MountType type) { | |
| 606 switch (type) { | |
| 607 case MOUNT_TYPE_DEVICE: | |
| 608 return "device"; | |
| 609 case MOUNT_TYPE_ARCHIVE: | |
| 610 return "file"; | |
| 611 case MOUNT_TYPE_NETWORK_STORAGE: | |
| 612 return "network"; | |
| 613 case MOUNT_TYPE_GDATA: | |
| 614 return "gdata"; | |
| 615 case MOUNT_TYPE_INVALID: | |
| 616 return "invalid"; | |
| 617 default: | |
| 618 NOTREACHED(); | |
| 619 } | |
| 620 return ""; | |
| 621 } | |
| 622 | |
| 623 // static | |
| 624 std::string DiskMountManager::MountConditionToString(MountCondition condition) { | |
| 625 switch (condition) { | |
| 626 case MOUNT_CONDITION_NONE: | |
| 627 return ""; | |
| 628 case MOUNT_CONDITION_UNKNOWN_FILESYSTEM: | |
| 629 return "unknown_filesystem"; | |
| 630 case MOUNT_CONDITION_UNSUPPORTED_FILESYSTEM: | |
| 631 return "unsupported_filesystem"; | |
| 632 default: | |
| 633 NOTREACHED(); | |
| 634 } | |
| 635 return ""; | |
| 636 } | |
| 637 | |
| 638 // static | |
| 639 MountType DiskMountManager::MountTypeFromString(const std::string& type_str) { | |
| 640 if (type_str == "device") | |
| 641 return MOUNT_TYPE_DEVICE; | |
| 642 else if (type_str == "network") | |
| 643 return MOUNT_TYPE_NETWORK_STORAGE; | |
| 644 else if (type_str == "file") | |
| 645 return MOUNT_TYPE_ARCHIVE; | |
| 646 else if (type_str == "gdata") | |
| 647 return MOUNT_TYPE_GDATA; | |
| 648 else | |
| 649 return MOUNT_TYPE_INVALID; | |
| 650 } | |
| 651 | |
| 652 // static | |
| 653 std::string DiskMountManager::DeviceTypeToString(DeviceType type) { | |
| 654 switch (type) { | |
| 655 case DEVICE_TYPE_USB: | |
| 656 return "usb"; | |
| 657 case DEVICE_TYPE_SD: | |
| 658 return "sd"; | |
| 659 case DEVICE_TYPE_OPTICAL_DISC: | |
| 660 return "optical"; | |
| 661 case DEVICE_TYPE_MOBILE: | |
| 662 return "mobile"; | |
| 663 default: | |
| 664 return "unknown"; | |
| 665 } | |
| 666 } | |
| 667 | |
| 668 // static | |
| 669 void DiskMountManager::Initialize() { | |
| 670 if (g_disk_mount_manager) { | |
| 671 LOG(WARNING) << "DiskMountManager was already initialized"; | |
| 672 return; | |
| 673 } | |
| 674 g_disk_mount_manager = new DiskMountManagerImpl(); | |
| 675 VLOG(1) << "DiskMountManager initialized"; | |
| 676 } | |
| 677 | |
| 678 // static | |
| 679 void DiskMountManager::InitializeForTesting( | |
| 680 DiskMountManager* disk_mount_manager) { | |
| 681 if (g_disk_mount_manager) { | |
| 682 LOG(WARNING) << "DiskMountManager was already initialized"; | |
| 683 return; | |
| 684 } | |
| 685 g_disk_mount_manager = disk_mount_manager; | |
| 686 VLOG(1) << "DiskMountManager initialized"; | |
| 687 } | |
| 688 | |
| 689 // static | |
| 690 void DiskMountManager::Shutdown() { | |
| 691 if (!g_disk_mount_manager) { | |
| 692 LOG(WARNING) << "DiskMountManager::Shutdown() called with NULL manager"; | |
| 693 return; | |
| 694 } | |
| 695 delete g_disk_mount_manager; | |
| 696 g_disk_mount_manager = NULL; | |
| 697 VLOG(1) << "DiskMountManager Shutdown completed"; | |
| 698 } | |
| 699 | |
| 700 // static | |
| 701 DiskMountManager* DiskMountManager::GetInstance() { | |
| 702 return g_disk_mount_manager; | |
| 703 } | |
| 704 | |
| 705 } // namespace disks | |
| 706 } // namespace chromeos | |
| OLD | NEW |