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