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 "chromeos/disks/disk_mount_manager.h" 6 7 #include <map> 8 #include <set> 9 10 #include "base/bind.h" 11 #include "base/memory/weak_ptr.h" 12 #include "base/observer_list.h" 13 #include "base/stl_util.h" 14 #include "base/strings/string_util.h" 15 #include "chromeos/dbus/dbus_thread_manager.h" 16 17 namespace chromeos { 18 namespace disks { 19 20 namespace { 21 22 const char kDeviceNotFound[] = "Device could not be found"; 23 24 DiskMountManager* g_disk_mount_manager = NULL; 25 26 // The DiskMountManager implementation. 27 class DiskMountManagerImpl : public DiskMountManager { 28 public: 29 DiskMountManagerImpl() : weak_ptr_factory_(this) { 30 DBusThreadManager* dbus_thread_manager = DBusThreadManager::Get(); 31 DCHECK(dbus_thread_manager); 32 cros_disks_client_ = dbus_thread_manager->GetCrosDisksClient(); 33 DCHECK(cros_disks_client_); 34 cros_disks_client_->SetMountEventHandler( 35 base::Bind(&DiskMountManagerImpl::OnMountEvent, 36 weak_ptr_factory_.GetWeakPtr())); 37 cros_disks_client_->SetMountCompletedHandler( 38 base::Bind(&DiskMountManagerImpl::OnMountCompleted, 39 weak_ptr_factory_.GetWeakPtr())); 40 cros_disks_client_->SetFormatCompletedHandler( 41 base::Bind(&DiskMountManagerImpl::OnFormatCompleted, 42 weak_ptr_factory_.GetWeakPtr())); 43 } 44 45 virtual ~DiskMountManagerImpl() { 46 STLDeleteContainerPairSecondPointers(disks_.begin(), disks_.end()); 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(MountEntry(MOUNT_ERROR_INTERNAL, source_path, type, 69 "")); 70 return; 71 } 72 } 73 cros_disks_client_->Mount( 74 source_path, 75 source_format, 76 mount_label, 77 // When succeeds, OnMountCompleted will be called by 78 // "MountCompleted" signal instead. 79 base::Bind(&base::DoNothing), 80 base::Bind(&DiskMountManagerImpl::OnMountCompleted, 81 weak_ptr_factory_.GetWeakPtr(), 82 MountEntry(MOUNT_ERROR_INTERNAL, source_path, type, ""))); 83 } 84 85 // DiskMountManager override. 86 virtual void UnmountPath(const std::string& mount_path, 87 UnmountOptions options, 88 const UnmountPathCallback& callback) OVERRIDE { 89 UnmountChildMounts(mount_path); 90 cros_disks_client_->Unmount(mount_path, options, 91 base::Bind(&DiskMountManagerImpl::OnUnmountPath, 92 weak_ptr_factory_.GetWeakPtr(), 93 callback, 94 true, 95 mount_path), 96 base::Bind(&DiskMountManagerImpl::OnUnmountPath, 97 weak_ptr_factory_.GetWeakPtr(), 98 callback, 99 false, 100 mount_path)); 101 } 102 103 // DiskMountManager override. 104 virtual void FormatMountedDevice(const std::string& mount_path) OVERRIDE { 105 MountPointMap::const_iterator mount_point = mount_points_.find(mount_path); 106 if (mount_point == mount_points_.end()) { 107 LOG(ERROR) << "Mount point with path \"" << mount_path << "\" not found."; 108 OnFormatCompleted(FORMAT_ERROR_UNKNOWN, mount_path); 109 return; 110 } 111 112 std::string device_path = mount_point->second.source_path; 113 DiskMap::const_iterator disk = disks_.find(device_path); 114 if (disk == disks_.end()) { 115 LOG(ERROR) << "Device with path \"" << device_path << "\" not found."; 116 OnFormatCompleted(FORMAT_ERROR_UNKNOWN, device_path); 117 return; 118 } 119 120 UnmountPath(disk->second->mount_path(), 121 UNMOUNT_OPTIONS_NONE, 122 base::Bind(&DiskMountManagerImpl::OnUnmountPathForFormat, 123 weak_ptr_factory_.GetWeakPtr(), 124 device_path)); 125 } 126 127 // DiskMountManager override. 128 virtual void UnmountDeviceRecursively( 129 const std::string& device_path, 130 const UnmountDeviceRecursivelyCallbackType& callback) OVERRIDE { 131 std::vector<std::string> devices_to_unmount; 132 133 // Get list of all devices to unmount. 134 int device_path_len = device_path.length(); 135 for (DiskMap::iterator it = disks_.begin(); it != disks_.end(); ++it) { 136 if (!it->second->mount_path().empty() && 137 strncmp(device_path.c_str(), it->second->device_path().c_str(), 138 device_path_len) == 0) { 139 devices_to_unmount.push_back(it->second->mount_path()); 140 } 141 } 142 143 // We should detect at least original device. 144 if (devices_to_unmount.empty()) { 145 if (disks_.find(device_path) == disks_.end()) { 146 LOG(WARNING) << "Unmount recursive request failed for device " 147 << device_path << ", with error: " << kDeviceNotFound; 148 callback.Run(false); 149 return; 150 } 151 152 // Nothing to unmount. 153 callback.Run(true); 154 return; 155 } 156 157 // We will send the same callback data object to all Unmount calls and use 158 // it to syncronize callbacks. 159 // Note: this implementation has a potential memory leak issue. For 160 // example if this instance is destructed before all the callbacks for 161 // Unmount are invoked, the memory pointed by |cb_data| will be leaked. 162 // It is because the UnmountDeviceRecursivelyCallbackData keeps how 163 // many times OnUnmountDeviceRecursively callback is called and when 164 // all the callbacks are called, |cb_data| will be deleted in the method. 165 // However destructing the instance before all callback invocations will 166 // cancel all pending callbacks, so that the |cb_data| would never be 167 // deleted. 168 // Fortunately, in the real scenario, the instance will be destructed 169 // only for ShutDown. So, probably the memory would rarely be leaked. 170 // TODO(hidehiko): Fix the issue. 171 UnmountDeviceRecursivelyCallbackData* cb_data = 172 new UnmountDeviceRecursivelyCallbackData( 173 callback, devices_to_unmount.size()); 174 for (size_t i = 0; i < devices_to_unmount.size(); ++i) { 175 cros_disks_client_->Unmount( 176 devices_to_unmount[i], 177 UNMOUNT_OPTIONS_NONE, 178 base::Bind(&DiskMountManagerImpl::OnUnmountDeviceRecursively, 179 weak_ptr_factory_.GetWeakPtr(), 180 cb_data, 181 true, 182 devices_to_unmount[i]), 183 base::Bind(&DiskMountManagerImpl::OnUnmountDeviceRecursively, 184 weak_ptr_factory_.GetWeakPtr(), 185 cb_data, 186 false, 187 devices_to_unmount[i])); 188 } 189 } 190 191 // DiskMountManager override. 192 virtual void RequestMountInfoRefresh() OVERRIDE { 193 cros_disks_client_->EnumerateAutoMountableDevices( 194 base::Bind(&DiskMountManagerImpl::OnRequestMountInfo, 195 weak_ptr_factory_.GetWeakPtr()), 196 base::Bind(&base::DoNothing)); 197 } 198 199 // DiskMountManager override. 200 virtual const DiskMap& disks() const OVERRIDE { return disks_; } 201 202 // DiskMountManager override. 203 virtual const Disk* FindDiskBySourcePath(const std::string& source_path) 204 const OVERRIDE { 205 DiskMap::const_iterator disk_it = disks_.find(source_path); 206 return disk_it == disks_.end() ? NULL : disk_it->second; 207 } 208 209 // DiskMountManager override. 210 virtual const MountPointMap& mount_points() const OVERRIDE { 211 return mount_points_; 212 } 213 214 // DiskMountManager override. 215 virtual bool AddDiskForTest(Disk* disk) OVERRIDE { 216 if (disks_.find(disk->device_path()) != disks_.end()) { 217 LOG(ERROR) << "Attempt to add a duplicate disk"; 218 return false; 219 } 220 221 disks_.insert(std::make_pair(disk->device_path(), disk)); 222 return true; 223 } 224 225 // DiskMountManager override. 226 // Corresponding disk should be added to the manager before this is called. 227 virtual bool AddMountPointForTest( 228 const MountPointInfo& mount_point) OVERRIDE { 229 if (mount_points_.find(mount_point.mount_path) != mount_points_.end()) { 230 LOG(ERROR) << "Attempt to add a duplicate mount point"; 231 return false; 232 } 233 if (mount_point.mount_type == chromeos::MOUNT_TYPE_DEVICE && 234 disks_.find(mount_point.source_path) == disks_.end()) { 235 LOG(ERROR) << "Device mount points must have a disk entry."; 236 return false; 237 } 238 239 mount_points_.insert(std::make_pair(mount_point.mount_path, mount_point)); 240 return true; 241 } 242 243 private: 244 struct UnmountDeviceRecursivelyCallbackData { 245 UnmountDeviceRecursivelyCallbackData( 246 const UnmountDeviceRecursivelyCallbackType& in_callback, 247 int in_num_pending_callbacks) 248 : callback(in_callback), 249 num_pending_callbacks(in_num_pending_callbacks) { 250 } 251 252 const UnmountDeviceRecursivelyCallbackType callback; 253 size_t num_pending_callbacks; 254 }; 255 256 // Unmounts all mount points whose source path is transitively parented by 257 // |mount_path|. 258 void UnmountChildMounts(const std::string& mount_path_in) { 259 std::string mount_path = mount_path_in; 260 // Let's make sure mount path has trailing slash. 261 if (mount_path[mount_path.length() - 1] != '/') 262 mount_path += '/'; 263 264 for (MountPointMap::iterator it = mount_points_.begin(); 265 it != mount_points_.end(); 266 ++it) { 267 if (StartsWithASCII(it->second.source_path, mount_path, 268 true /*case sensitive*/)) { 269 // TODO(tbarzic): Handle the case where this fails. 270 UnmountPath(it->second.mount_path, 271 UNMOUNT_OPTIONS_NONE, 272 UnmountPathCallback()); 273 } 274 } 275 } 276 277 // Callback for UnmountDeviceRecursively. 278 void OnUnmountDeviceRecursively( 279 UnmountDeviceRecursivelyCallbackData* cb_data, 280 bool success, 281 const std::string& mount_path) { 282 if (success) { 283 // Do standard processing for Unmount event. 284 OnUnmountPath(UnmountPathCallback(), true, mount_path); 285 VLOG(1) << mount_path << " unmounted."; 286 } 287 // This is safe as long as all callbacks are called on the same thread as 288 // UnmountDeviceRecursively. 289 cb_data->num_pending_callbacks--; 290 291 if (cb_data->num_pending_callbacks == 0) { 292 // This code has a problem that the |success| status used here is for the 293 // last "unmount" callback, but not whether all unmounting is succeeded. 294 // TODO(hidehiko): Fix the issue. 295 cb_data->callback.Run(success); 296 delete cb_data; 297 } 298 } 299 300 // Callback to handle MountCompleted signal and Mount method call failure. 301 void OnMountCompleted(const MountEntry& entry) { 302 MountCondition mount_condition = MOUNT_CONDITION_NONE; 303 if (entry.mount_type() == MOUNT_TYPE_DEVICE) { 304 if (entry.error_code() == MOUNT_ERROR_UNKNOWN_FILESYSTEM) { 305 mount_condition = MOUNT_CONDITION_UNKNOWN_FILESYSTEM; 306 } 307 if (entry.error_code() == MOUNT_ERROR_UNSUPPORTED_FILESYSTEM) { 308 mount_condition = MOUNT_CONDITION_UNSUPPORTED_FILESYSTEM; 309 } 310 } 311 const MountPointInfo mount_info(entry.source_path(), 312 entry.mount_path(), 313 entry.mount_type(), 314 mount_condition); 315 316 NotifyMountStatusUpdate(MOUNTING, entry.error_code(), mount_info); 317 318 // If the device is corrupted but it's still possible to format it, it will 319 // be fake mounted. 320 if ((entry.error_code() == MOUNT_ERROR_NONE || 321 mount_info.mount_condition) && 322 mount_points_.find(mount_info.mount_path) == mount_points_.end()) { 323 mount_points_.insert(MountPointMap::value_type(mount_info.mount_path, 324 mount_info)); 325 } 326 if ((entry.error_code() == MOUNT_ERROR_NONE || 327 mount_info.mount_condition) && 328 mount_info.mount_type == MOUNT_TYPE_DEVICE && 329 !mount_info.source_path.empty() && 330 !mount_info.mount_path.empty()) { 331 DiskMap::iterator iter = disks_.find(mount_info.source_path); 332 if (iter == disks_.end()) { 333 // disk might have been removed by now? 334 return; 335 } 336 Disk* disk = iter->second; 337 DCHECK(disk); 338 disk->set_mount_path(mount_info.mount_path); 339 } 340 } 341 342 // Callback for UnmountPath. 343 void OnUnmountPath(const UnmountPathCallback& callback, 344 bool success, 345 const std::string& mount_path) { 346 MountPointMap::iterator mount_points_it = mount_points_.find(mount_path); 347 if (mount_points_it == mount_points_.end()) { 348 // The path was unmounted, but not as a result of this unmount request, 349 // so return error. 350 if (!callback.is_null()) 351 callback.Run(MOUNT_ERROR_INTERNAL); 352 return; 353 } 354 355 NotifyMountStatusUpdate( 356 UNMOUNTING, 357 success ? MOUNT_ERROR_NONE : MOUNT_ERROR_INTERNAL, 358 MountPointInfo(mount_points_it->second.source_path, 359 mount_points_it->second.mount_path, 360 mount_points_it->second.mount_type, 361 mount_points_it->second.mount_condition)); 362 363 std::string path(mount_points_it->second.source_path); 364 if (success) 365 mount_points_.erase(mount_points_it); 366 367 DiskMap::iterator disk_iter = disks_.find(path); 368 if (disk_iter != disks_.end()) { 369 DCHECK(disk_iter->second); 370 if (success) 371 disk_iter->second->clear_mount_path(); 372 } 373 374 if (!callback.is_null()) 375 callback.Run(success ? MOUNT_ERROR_NONE : MOUNT_ERROR_INTERNAL); 376 } 377 378 void OnUnmountPathForFormat(const std::string& device_path, 379 MountError error_code) { 380 if (error_code == MOUNT_ERROR_NONE && 381 disks_.find(device_path) != disks_.end()) { 382 FormatUnmountedDevice(device_path); 383 } else { 384 OnFormatCompleted(FORMAT_ERROR_UNKNOWN, device_path); 385 } 386 } 387 388 // Starts device formatting. 389 void FormatUnmountedDevice(const std::string& device_path) { 390 DiskMap::const_iterator disk = disks_.find(device_path); 391 DCHECK(disk != disks_.end() && disk->second->mount_path().empty()); 392 393 const char kFormatVFAT[] = "vfat"; 394 cros_disks_client_->Format( 395 device_path, 396 kFormatVFAT, 397 base::Bind(&DiskMountManagerImpl::OnFormatStarted, 398 weak_ptr_factory_.GetWeakPtr(), 399 device_path), 400 base::Bind(&DiskMountManagerImpl::OnFormatCompleted, 401 weak_ptr_factory_.GetWeakPtr(), 402 FORMAT_ERROR_UNKNOWN, 403 device_path)); 404 } 405 406 // Callback for Format. 407 void OnFormatStarted(const std::string& device_path) { 408 NotifyFormatStatusUpdate(FORMAT_STARTED, FORMAT_ERROR_NONE, device_path); 409 } 410 411 // Callback to handle FormatCompleted signal and Format method call failure. 412 void OnFormatCompleted(FormatError error_code, 413 const std::string& device_path) { 414 NotifyFormatStatusUpdate(FORMAT_COMPLETED, error_code, device_path); 415 } 416 417 // Callbcak for GetDeviceProperties. 418 void OnGetDeviceProperties(const DiskInfo& disk_info) { 419 // TODO(zelidrag): Find a better way to filter these out before we 420 // fetch the properties: 421 // Ignore disks coming from the device we booted the system from. 422 if (disk_info.on_boot_device()) 423 return; 424 425 LOG(WARNING) << "Found disk " << disk_info.device_path(); 426 // Delete previous disk info for this path: 427 bool is_new = true; 428 DiskMap::iterator iter = disks_.find(disk_info.device_path()); 429 if (iter != disks_.end()) { 430 delete iter->second; 431 disks_.erase(iter); 432 is_new = false; 433 } 434 Disk* disk = new Disk(disk_info.device_path(), 435 disk_info.mount_path(), 436 disk_info.system_path(), 437 disk_info.file_path(), 438 disk_info.label(), 439 disk_info.drive_label(), 440 disk_info.vendor_id(), 441 disk_info.vendor_name(), 442 disk_info.product_id(), 443 disk_info.product_name(), 444 disk_info.uuid(), 445 FindSystemPathPrefix(disk_info.system_path()), 446 disk_info.device_type(), 447 disk_info.total_size_in_bytes(), 448 disk_info.is_drive(), 449 disk_info.is_read_only(), 450 disk_info.has_media(), 451 disk_info.on_boot_device(), 452 disk_info.is_hidden()); 453 disks_.insert(std::make_pair(disk_info.device_path(), disk)); 454 NotifyDiskStatusUpdate(is_new ? DISK_ADDED : DISK_CHANGED, disk); 455 } 456 457 // Callbcak for RequestMountInfo. 458 void OnRequestMountInfo(const std::vector<std::string>& devices) { 459 std::set<std::string> current_device_set; 460 if (!devices.empty()) { 461 // Initiate properties fetch for all removable disks, 462 for (size_t i = 0; i < devices.size(); i++) { 463 current_device_set.insert(devices[i]); 464 // Initiate disk property retrieval for each relevant device path. 465 cros_disks_client_->GetDeviceProperties( 466 devices[i], 467 base::Bind(&DiskMountManagerImpl::OnGetDeviceProperties, 468 weak_ptr_factory_.GetWeakPtr()), 469 base::Bind(&base::DoNothing)); 470 } 471 } 472 // Search and remove disks that are no longer present. 473 for (DiskMap::iterator iter = disks_.begin(); iter != disks_.end(); ) { 474 if (current_device_set.find(iter->first) == current_device_set.end()) { 475 Disk* disk = iter->second; 476 NotifyDiskStatusUpdate(DISK_REMOVED, disk); 477 delete iter->second; 478 disks_.erase(iter++); 479 } else { 480 ++iter; 481 } 482 } 483 } 484 485 // Callback to handle mount event signals. 486 void OnMountEvent(MountEventType event, const std::string& device_path_arg) { 487 // Take a copy of the argument so we can modify it below. 488 std::string device_path = device_path_arg; 489 switch (event) { 490 case CROS_DISKS_DISK_ADDED: { 491 cros_disks_client_->GetDeviceProperties( 492 device_path, 493 base::Bind(&DiskMountManagerImpl::OnGetDeviceProperties, 494 weak_ptr_factory_.GetWeakPtr()), 495 base::Bind(&base::DoNothing)); 496 break; 497 } 498 case CROS_DISKS_DISK_REMOVED: { 499 // Search and remove disks that are no longer present. 500 DiskMountManager::DiskMap::iterator iter = disks_.find(device_path); 501 if (iter != disks_.end()) { 502 Disk* disk = iter->second; 503 NotifyDiskStatusUpdate(DISK_REMOVED, disk); 504 delete iter->second; 505 disks_.erase(iter); 506 } 507 break; 508 } 509 case CROS_DISKS_DEVICE_ADDED: { 510 system_path_prefixes_.insert(device_path); 511 NotifyDeviceStatusUpdate(DEVICE_ADDED, device_path); 512 break; 513 } 514 case CROS_DISKS_DEVICE_REMOVED: { 515 system_path_prefixes_.erase(device_path); 516 NotifyDeviceStatusUpdate(DEVICE_REMOVED, device_path); 517 break; 518 } 519 case CROS_DISKS_DEVICE_SCANNED: { 520 NotifyDeviceStatusUpdate(DEVICE_SCANNED, device_path); 521 break; 522 } 523 default: { 524 LOG(ERROR) << "Unknown event: " << event; 525 } 526 } 527 } 528 529 // Notifies all observers about disk status update. 530 void NotifyDiskStatusUpdate(DiskEvent event, 531 const Disk* disk) { 532 FOR_EACH_OBSERVER(Observer, observers_, OnDiskEvent(event, disk)); 533 } 534 535 // Notifies all observers about device status update. 536 void NotifyDeviceStatusUpdate(DeviceEvent event, 537 const std::string& device_path) { 538 FOR_EACH_OBSERVER(Observer, observers_, OnDeviceEvent(event, device_path)); 539 } 540 541 // Notifies all observers about mount completion. 542 void NotifyMountStatusUpdate(MountEvent event, 543 MountError error_code, 544 const MountPointInfo& mount_info) { 545 FOR_EACH_OBSERVER(Observer, observers_, 546 OnMountEvent(event, error_code, mount_info)); 547 } 548 549 void NotifyFormatStatusUpdate(FormatEvent event, 550 FormatError error_code, 551 const std::string& device_path) { 552 FOR_EACH_OBSERVER(Observer, observers_, 553 OnFormatEvent(event, error_code, device_path)); 554 } 555 556 // Finds system path prefix from |system_path|. 557 const std::string& FindSystemPathPrefix(const std::string& system_path) { 558 if (system_path.empty()) 559 return base::EmptyString(); 560 for (SystemPathPrefixSet::const_iterator it = system_path_prefixes_.begin(); 561 it != system_path_prefixes_.end(); 562 ++it) { 563 const std::string& prefix = *it; 564 if (StartsWithASCII(system_path, prefix, true)) 565 return prefix; 566 } 567 return base::EmptyString(); 568 } 569 570 // Mount event change observers. 571 ObserverList<Observer> observers_; 572 573 CrosDisksClient* cros_disks_client_; 574 575 // The list of disks found. 576 DiskMountManager::DiskMap disks_; 577 578 DiskMountManager::MountPointMap mount_points_; 579 580 typedef std::set<std::string> SystemPathPrefixSet; 581 SystemPathPrefixSet system_path_prefixes_; 582 583 base::WeakPtrFactory<DiskMountManagerImpl> weak_ptr_factory_; 584 585 DISALLOW_COPY_AND_ASSIGN(DiskMountManagerImpl); 586 }; 587 588 } // namespace 589 590 DiskMountManager::Disk::Disk(const std::string& device_path, 591 const std::string& mount_path, 592 const std::string& system_path, 593 const std::string& file_path, 594 const std::string& device_label, 595 const std::string& drive_label, 596 const std::string& vendor_id, 597 const std::string& vendor_name, 598 const std::string& product_id, 599 const std::string& product_name, 600 const std::string& fs_uuid, 601 const std::string& system_path_prefix, 602 DeviceType device_type, 603 uint64 total_size_in_bytes, 604 bool is_parent, 605 bool is_read_only, 606 bool has_media, 607 bool on_boot_device, 608 bool is_hidden) 609 : device_path_(device_path), 610 mount_path_(mount_path), 611 system_path_(system_path), 612 file_path_(file_path), 613 device_label_(device_label), 614 drive_label_(drive_label), 615 vendor_id_(vendor_id), 616 vendor_name_(vendor_name), 617 product_id_(product_id), 618 product_name_(product_name), 619 fs_uuid_(fs_uuid), 620 system_path_prefix_(system_path_prefix), 621 device_type_(device_type), 622 total_size_in_bytes_(total_size_in_bytes), 623 is_parent_(is_parent), 624 is_read_only_(is_read_only), 625 has_media_(has_media), 626 on_boot_device_(on_boot_device), 627 is_hidden_(is_hidden) { 628 } 629 630 DiskMountManager::Disk::~Disk() {} 631 632 bool DiskMountManager::AddDiskForTest(Disk* disk) { 633 return false; 634 } 635 636 bool DiskMountManager::AddMountPointForTest(const MountPointInfo& mount_point) { 637 return false; 638 } 639 640 // static 641 std::string DiskMountManager::MountConditionToString(MountCondition condition) { 642 switch (condition) { 643 case MOUNT_CONDITION_NONE: 644 return ""; 645 case MOUNT_CONDITION_UNKNOWN_FILESYSTEM: 646 return "unknown_filesystem"; 647 case MOUNT_CONDITION_UNSUPPORTED_FILESYSTEM: 648 return "unsupported_filesystem"; 649 default: 650 NOTREACHED(); 651 } 652 return ""; 653 } 654 655 // static 656 std::string DiskMountManager::DeviceTypeToString(DeviceType type) { 657 switch (type) { 658 case DEVICE_TYPE_USB: 659 return "usb"; 660 case DEVICE_TYPE_SD: 661 return "sd"; 662 case DEVICE_TYPE_OPTICAL_DISC: 663 return "optical"; 664 case DEVICE_TYPE_MOBILE: 665 return "mobile"; 666 default: 667 return "unknown"; 668 } 669 } 670 671 // static 672 void DiskMountManager::Initialize() { 673 if (g_disk_mount_manager) { 674 LOG(WARNING) << "DiskMountManager was already initialized"; 675 return; 676 } 677 g_disk_mount_manager = new DiskMountManagerImpl(); 678 VLOG(1) << "DiskMountManager initialized"; 679 } 680 681 // static 682 void DiskMountManager::InitializeForTesting( 683 DiskMountManager* disk_mount_manager) { 684 if (g_disk_mount_manager) { 685 LOG(WARNING) << "DiskMountManager was already initialized"; 686 return; 687 } 688 g_disk_mount_manager = disk_mount_manager; 689 VLOG(1) << "DiskMountManager initialized"; 690 } 691 692 // static 693 void DiskMountManager::Shutdown() { 694 if (!g_disk_mount_manager) { 695 LOG(WARNING) << "DiskMountManager::Shutdown() called with NULL manager"; 696 return; 697 } 698 delete g_disk_mount_manager; 699 g_disk_mount_manager = NULL; 700 VLOG(1) << "DiskMountManager Shutdown completed"; 701 } 702 703 // static 704 DiskMountManager* DiskMountManager::GetInstance() { 705 return g_disk_mount_manager; 706 } 707 708 } // namespace disks 709 } // namespace chromeos 710