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/dbus/cros_disks_client.h" 6 7 #include <map> 8 9 #include "base/bind.h" 10 #include "base/files/file_path.h" 11 #include "base/files/file_util.h" 12 #include "base/location.h" 13 #include "base/message_loop/message_loop_proxy.h" 14 #include "base/stl_util.h" 15 #include "base/strings/stringprintf.h" 16 #include "base/sys_info.h" 17 #include "base/task_runner_util.h" 18 #include "base/threading/worker_pool.h" 19 #include "base/values.h" 20 #include "dbus/bus.h" 21 #include "dbus/message.h" 22 #include "dbus/object_path.h" 23 #include "dbus/object_proxy.h" 24 #include "dbus/values_util.h" 25 #include "third_party/cros_system_api/dbus/service_constants.h" 26 27 namespace chromeos { 28 29 namespace { 30 31 const char* kDefaultMountOptions[] = { 32 "rw", 33 "nodev", 34 "noexec", 35 "nosuid", 36 }; 37 38 const char* kDefaultUnmountOptions[] = { 39 "force", 40 }; 41 42 const char kLazyUnmountOption[] = "lazy"; 43 44 const char kMountLabelOption[] = "mountlabel"; 45 46 // Checks if retrieved media type is in boundaries of DeviceMediaType. 47 bool IsValidMediaType(uint32 type) { 48 return type < static_cast<uint32>(cros_disks::DEVICE_MEDIA_NUM_VALUES); 49 } 50 51 // Translates enum used in cros-disks to enum used in Chrome. 52 // Note that we could just do static_cast, but this is less sensitive to 53 // changes in cros-disks. 54 DeviceType DeviceMediaTypeToDeviceType(uint32 media_type_uint32) { 55 if (!IsValidMediaType(media_type_uint32)) 56 return DEVICE_TYPE_UNKNOWN; 57 58 cros_disks::DeviceMediaType media_type = 59 cros_disks::DeviceMediaType(media_type_uint32); 60 61 switch (media_type) { 62 case(cros_disks::DEVICE_MEDIA_UNKNOWN): 63 return DEVICE_TYPE_UNKNOWN; 64 case(cros_disks::DEVICE_MEDIA_USB): 65 return DEVICE_TYPE_USB; 66 case(cros_disks::DEVICE_MEDIA_SD): 67 return DEVICE_TYPE_SD; 68 case(cros_disks::DEVICE_MEDIA_OPTICAL_DISC): 69 return DEVICE_TYPE_OPTICAL_DISC; 70 case(cros_disks::DEVICE_MEDIA_MOBILE): 71 return DEVICE_TYPE_MOBILE; 72 case(cros_disks::DEVICE_MEDIA_DVD): 73 return DEVICE_TYPE_DVD; 74 default: 75 return DEVICE_TYPE_UNKNOWN; 76 } 77 } 78 79 bool ReadMountEntryFromDbus(dbus::MessageReader* reader, MountEntry* entry) { 80 uint32 error_code = 0; 81 std::string source_path; 82 uint32 mount_type = 0; 83 std::string mount_path; 84 if (!reader->PopUint32(&error_code) || 85 !reader->PopString(&source_path) || 86 !reader->PopUint32(&mount_type) || 87 !reader->PopString(&mount_path)) { 88 return false; 89 } 90 *entry = MountEntry(static_cast<MountError>(error_code), source_path, 91 static_cast<MountType>(mount_type), mount_path); 92 return true; 93 } 94 95 // The CrosDisksClient implementation. 96 class CrosDisksClientImpl : public CrosDisksClient { 97 public: 98 CrosDisksClientImpl() : proxy_(NULL), weak_ptr_factory_(this) {} 99 100 // CrosDisksClient override. 101 virtual void Mount(const std::string& source_path, 102 const std::string& source_format, 103 const std::string& mount_label, 104 const base::Closure& callback, 105 const base::Closure& error_callback) OVERRIDE { 106 dbus::MethodCall method_call(cros_disks::kCrosDisksInterface, 107 cros_disks::kMount); 108 dbus::MessageWriter writer(&method_call); 109 writer.AppendString(source_path); 110 writer.AppendString(source_format); 111 std::vector<std::string> mount_options(kDefaultMountOptions, 112 kDefaultMountOptions + 113 arraysize(kDefaultMountOptions)); 114 if (!mount_label.empty()) { 115 std::string mount_label_option = base::StringPrintf("%s=%s", 116 kMountLabelOption, 117 mount_label.c_str()); 118 mount_options.push_back(mount_label_option); 119 } 120 writer.AppendArrayOfStrings(mount_options); 121 proxy_->CallMethod(&method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, 122 base::Bind(&CrosDisksClientImpl::OnMount, 123 weak_ptr_factory_.GetWeakPtr(), 124 callback, 125 error_callback)); 126 } 127 128 // CrosDisksClient override. 129 virtual void Unmount(const std::string& device_path, 130 UnmountOptions options, 131 const base::Closure& callback, 132 const base::Closure& error_callback) OVERRIDE { 133 dbus::MethodCall method_call(cros_disks::kCrosDisksInterface, 134 cros_disks::kUnmount); 135 dbus::MessageWriter writer(&method_call); 136 writer.AppendString(device_path); 137 138 std::vector<std::string> unmount_options( 139 kDefaultUnmountOptions, 140 kDefaultUnmountOptions + arraysize(kDefaultUnmountOptions)); 141 if (options == UNMOUNT_OPTIONS_LAZY) 142 unmount_options.push_back(kLazyUnmountOption); 143 144 writer.AppendArrayOfStrings(unmount_options); 145 proxy_->CallMethod(&method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, 146 base::Bind(&CrosDisksClientImpl::OnUnmount, 147 weak_ptr_factory_.GetWeakPtr(), 148 callback, 149 error_callback)); 150 } 151 152 // CrosDisksClient override. 153 virtual void EnumerateAutoMountableDevices( 154 const EnumerateAutoMountableDevicesCallback& callback, 155 const base::Closure& error_callback) OVERRIDE { 156 dbus::MethodCall method_call(cros_disks::kCrosDisksInterface, 157 cros_disks::kEnumerateAutoMountableDevices); 158 proxy_->CallMethod( 159 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, 160 base::Bind(&CrosDisksClientImpl::OnEnumerateAutoMountableDevices, 161 weak_ptr_factory_.GetWeakPtr(), 162 callback, 163 error_callback)); 164 } 165 166 // CrosDisksClient override. 167 virtual void EnumerateMountEntries( 168 const EnumerateMountEntriesCallback& callback, 169 const base::Closure& error_callback) OVERRIDE { 170 dbus::MethodCall method_call(cros_disks::kCrosDisksInterface, 171 cros_disks::kEnumerateMountEntries); 172 proxy_->CallMethod( 173 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, 174 base::Bind(&CrosDisksClientImpl::OnEnumerateMountEntries, 175 weak_ptr_factory_.GetWeakPtr(), 176 callback, 177 error_callback)); 178 } 179 180 // CrosDisksClient override. 181 virtual void Format(const std::string& device_path, 182 const std::string& filesystem, 183 const base::Closure& callback, 184 const base::Closure& error_callback) OVERRIDE { 185 dbus::MethodCall method_call(cros_disks::kCrosDisksInterface, 186 cros_disks::kFormat); 187 dbus::MessageWriter writer(&method_call); 188 writer.AppendString(device_path); 189 writer.AppendString(filesystem); 190 // No format option is currently specified, but we can later use this 191 // argument to specify options for the format operation. 192 std::vector<std::string> format_options; 193 writer.AppendArrayOfStrings(format_options); 194 proxy_->CallMethod(&method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, 195 base::Bind(&CrosDisksClientImpl::OnFormat, 196 weak_ptr_factory_.GetWeakPtr(), 197 callback, 198 error_callback)); 199 } 200 201 // CrosDisksClient override. 202 virtual void GetDeviceProperties( 203 const std::string& device_path, 204 const GetDevicePropertiesCallback& callback, 205 const base::Closure& error_callback) OVERRIDE { 206 dbus::MethodCall method_call(cros_disks::kCrosDisksInterface, 207 cros_disks::kGetDeviceProperties); 208 dbus::MessageWriter writer(&method_call); 209 writer.AppendString(device_path); 210 proxy_->CallMethod(&method_call, 211 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, 212 base::Bind(&CrosDisksClientImpl::OnGetDeviceProperties, 213 weak_ptr_factory_.GetWeakPtr(), 214 device_path, 215 callback, 216 error_callback)); 217 } 218 219 // CrosDisksClient override. 220 virtual void SetMountEventHandler( 221 const MountEventHandler& mount_event_handler) OVERRIDE { 222 static const SignalEventTuple kSignalEventTuples[] = { 223 { cros_disks::kDeviceAdded, CROS_DISKS_DEVICE_ADDED }, 224 { cros_disks::kDeviceScanned, CROS_DISKS_DEVICE_SCANNED }, 225 { cros_disks::kDeviceRemoved, CROS_DISKS_DEVICE_REMOVED }, 226 { cros_disks::kDiskAdded, CROS_DISKS_DISK_ADDED }, 227 { cros_disks::kDiskChanged, CROS_DISKS_DISK_CHANGED }, 228 { cros_disks::kDiskRemoved, CROS_DISKS_DISK_REMOVED }, 229 }; 230 const size_t kNumSignalEventTuples = arraysize(kSignalEventTuples); 231 232 for (size_t i = 0; i < kNumSignalEventTuples; ++i) { 233 proxy_->ConnectToSignal( 234 cros_disks::kCrosDisksInterface, 235 kSignalEventTuples[i].signal_name, 236 base::Bind(&CrosDisksClientImpl::OnMountEvent, 237 weak_ptr_factory_.GetWeakPtr(), 238 kSignalEventTuples[i].event_type, 239 mount_event_handler), 240 base::Bind(&CrosDisksClientImpl::OnSignalConnected, 241 weak_ptr_factory_.GetWeakPtr())); 242 } 243 } 244 245 // CrosDisksClient override. 246 virtual void SetMountCompletedHandler( 247 const MountCompletedHandler& mount_completed_handler) OVERRIDE { 248 proxy_->ConnectToSignal( 249 cros_disks::kCrosDisksInterface, 250 cros_disks::kMountCompleted, 251 base::Bind(&CrosDisksClientImpl::OnMountCompleted, 252 weak_ptr_factory_.GetWeakPtr(), 253 mount_completed_handler), 254 base::Bind(&CrosDisksClientImpl::OnSignalConnected, 255 weak_ptr_factory_.GetWeakPtr())); 256 } 257 258 // CrosDisksClient override. 259 virtual void SetFormatCompletedHandler( 260 const FormatCompletedHandler& format_completed_handler) OVERRIDE { 261 proxy_->ConnectToSignal( 262 cros_disks::kCrosDisksInterface, 263 cros_disks::kFormatCompleted, 264 base::Bind(&CrosDisksClientImpl::OnFormatCompleted, 265 weak_ptr_factory_.GetWeakPtr(), 266 format_completed_handler), 267 base::Bind(&CrosDisksClientImpl::OnSignalConnected, 268 weak_ptr_factory_.GetWeakPtr())); 269 } 270 271 protected: 272 virtual void Init(dbus::Bus* bus) OVERRIDE { 273 proxy_ = bus->GetObjectProxy( 274 cros_disks::kCrosDisksServiceName, 275 dbus::ObjectPath(cros_disks::kCrosDisksServicePath)); 276 } 277 278 private: 279 // A struct to contain a pair of signal name and mount event type. 280 // Used by SetMountEventHandler. 281 struct SignalEventTuple { 282 const char *signal_name; 283 MountEventType event_type; 284 }; 285 286 // Handles the result of Mount and calls |callback| or |error_callback|. 287 void OnMount(const base::Closure& callback, 288 const base::Closure& error_callback, 289 dbus::Response* response) { 290 if (!response) { 291 error_callback.Run(); 292 return; 293 } 294 callback.Run(); 295 } 296 297 // Handles the result of Unmount and calls |callback| or |error_callback|. 298 void OnUnmount(const base::Closure& callback, 299 const base::Closure& error_callback, 300 dbus::Response* response) { 301 if (!response) { 302 error_callback.Run(); 303 return; 304 } 305 306 // Temporarly allow Unmount method to report failure both by setting dbus 307 // error (in which case response is not set) and by returning mount error 308 // different from MOUNT_ERROR_NONE. This is done so we can change Unmount 309 // method to return mount error (http://crbug.com/288974) without breaking 310 // Chrome. 311 // TODO(tbarzic): When Unmount implementation is changed on cros disks side, 312 // make this fail if reader is not able to read the error code value from 313 // the response. 314 dbus::MessageReader reader(response); 315 uint32 error_code = 0; 316 if (reader.PopUint32(&error_code) && 317 static_cast<MountError>(error_code) != MOUNT_ERROR_NONE) { 318 error_callback.Run(); 319 return; 320 } 321 322 callback.Run(); 323 } 324 325 // Handles the result of EnumerateAutoMountableDevices and calls |callback| or 326 // |error_callback|. 327 void OnEnumerateAutoMountableDevices( 328 const EnumerateAutoMountableDevicesCallback& callback, 329 const base::Closure& error_callback, 330 dbus::Response* response) { 331 if (!response) { 332 error_callback.Run(); 333 return; 334 } 335 dbus::MessageReader reader(response); 336 std::vector<std::string> device_paths; 337 if (!reader.PopArrayOfStrings(&device_paths)) { 338 LOG(ERROR) << "Invalid response: " << response->ToString(); 339 error_callback.Run(); 340 return; 341 } 342 callback.Run(device_paths); 343 } 344 345 // Handles the result of EnumerateMountEntries and calls |callback| or 346 // |error_callback|. 347 void OnEnumerateMountEntries( 348 const EnumerateMountEntriesCallback& callback, 349 const base::Closure& error_callback, 350 dbus::Response* response) { 351 if (!response) { 352 error_callback.Run(); 353 return; 354 } 355 356 dbus::MessageReader reader(response); 357 dbus::MessageReader array_reader(NULL); 358 if (!reader.PopArray(&array_reader)) { 359 LOG(ERROR) << "Invalid response: " << response->ToString(); 360 error_callback.Run(); 361 return; 362 } 363 364 std::vector<MountEntry> entries; 365 while (array_reader.HasMoreData()) { 366 MountEntry entry; 367 dbus::MessageReader sub_reader(NULL); 368 if (!array_reader.PopStruct(&sub_reader) || 369 !ReadMountEntryFromDbus(&sub_reader, &entry)) { 370 LOG(ERROR) << "Invalid response: " << response->ToString(); 371 error_callback.Run(); 372 return; 373 } 374 entries.push_back(entry); 375 } 376 callback.Run(entries); 377 } 378 379 // Handles the result of Format and calls |callback| or |error_callback|. 380 void OnFormat(const base::Closure& callback, 381 const base::Closure& error_callback, 382 dbus::Response* response) { 383 if (!response) { 384 error_callback.Run(); 385 return; 386 } 387 callback.Run(); 388 } 389 390 // Handles the result of GetDeviceProperties and calls |callback| or 391 // |error_callback|. 392 void OnGetDeviceProperties(const std::string& device_path, 393 const GetDevicePropertiesCallback& callback, 394 const base::Closure& error_callback, 395 dbus::Response* response) { 396 if (!response) { 397 error_callback.Run(); 398 return; 399 } 400 DiskInfo disk(device_path, response); 401 callback.Run(disk); 402 } 403 404 // Handles mount event signals and calls |handler|. 405 void OnMountEvent(MountEventType event_type, 406 MountEventHandler handler, 407 dbus::Signal* signal) { 408 dbus::MessageReader reader(signal); 409 std::string device; 410 if (!reader.PopString(&device)) { 411 LOG(ERROR) << "Invalid signal: " << signal->ToString(); 412 return; 413 } 414 handler.Run(event_type, device); 415 } 416 417 // Handles MountCompleted signal and calls |handler|. 418 void OnMountCompleted(MountCompletedHandler handler, dbus::Signal* signal) { 419 dbus::MessageReader reader(signal); 420 MountEntry entry; 421 if (!ReadMountEntryFromDbus(&reader, &entry)) { 422 LOG(ERROR) << "Invalid signal: " << signal->ToString(); 423 return; 424 } 425 handler.Run(entry); 426 } 427 428 // Handles FormatCompleted signal and calls |handler|. 429 void OnFormatCompleted(FormatCompletedHandler handler, dbus::Signal* signal) { 430 dbus::MessageReader reader(signal); 431 uint32 error_code = 0; 432 std::string device_path; 433 if (!reader.PopUint32(&error_code) || !reader.PopString(&device_path)) { 434 LOG(ERROR) << "Invalid signal: " << signal->ToString(); 435 return; 436 } 437 handler.Run(static_cast<FormatError>(error_code), device_path); 438 } 439 440 // Handles the result of signal connection setup. 441 void OnSignalConnected(const std::string& interface, 442 const std::string& signal, 443 bool succeeded) { 444 LOG_IF(ERROR, !succeeded) << "Connect to " << interface << " " << 445 signal << " failed."; 446 } 447 448 dbus::ObjectProxy* proxy_; 449 450 // Note: This should remain the last member so it'll be destroyed and 451 // invalidate its weak pointers before any other members are destroyed. 452 base::WeakPtrFactory<CrosDisksClientImpl> weak_ptr_factory_; 453 454 DISALLOW_COPY_AND_ASSIGN(CrosDisksClientImpl); 455 }; 456 457 // A stub implementaion of CrosDisksClient. 458 class CrosDisksClientStubImpl : public CrosDisksClient { 459 public: 460 CrosDisksClientStubImpl() 461 : weak_ptr_factory_(this) {} 462 463 virtual ~CrosDisksClientStubImpl() {} 464 465 // CrosDisksClient overrides: 466 virtual void Init(dbus::Bus* bus) OVERRIDE {} 467 virtual void Mount(const std::string& source_path, 468 const std::string& source_format, 469 const std::string& mount_label, 470 const base::Closure& callback, 471 const base::Closure& error_callback) OVERRIDE { 472 // This stub implementation only accepts archive mount requests. 473 const MountType type = MOUNT_TYPE_ARCHIVE; 474 475 const base::FilePath mounted_path = GetArchiveMountPoint().Append( 476 base::FilePath::FromUTF8Unsafe(mount_label)); 477 478 // Already mounted path. 479 if (mounted_to_source_path_map_.count(mounted_path.value()) != 0) { 480 FinishMount(MOUNT_ERROR_PATH_ALREADY_MOUNTED, source_path, type, 481 std::string(), callback); 482 return; 483 } 484 485 // Perform fake mount. 486 base::PostTaskAndReplyWithResult( 487 base::WorkerPool::GetTaskRunner(true /* task_is_slow */).get(), 488 FROM_HERE, 489 base::Bind(&PerformFakeMount, source_path, mounted_path), 490 base::Bind(&CrosDisksClientStubImpl::ContinueMount, 491 weak_ptr_factory_.GetWeakPtr(), 492 source_path, 493 type, 494 callback, 495 mounted_path)); 496 } 497 498 virtual void Unmount(const std::string& device_path, 499 UnmountOptions options, 500 const base::Closure& callback, 501 const base::Closure& error_callback) OVERRIDE { 502 // Not mounted. 503 if (mounted_to_source_path_map_.count(device_path) == 0) { 504 base::MessageLoopProxy::current()->PostTask(FROM_HERE, error_callback); 505 return; 506 } 507 508 mounted_to_source_path_map_.erase(device_path); 509 510 // Remove the directory created in Mount(). 511 base::WorkerPool::PostTaskAndReply( 512 FROM_HERE, 513 base::Bind(base::IgnoreResult(&base::DeleteFile), 514 base::FilePath::FromUTF8Unsafe(device_path), 515 true /* recursive */), 516 callback, 517 true /* task_is_slow */); 518 } 519 520 virtual void EnumerateAutoMountableDevices( 521 const EnumerateAutoMountableDevicesCallback& callback, 522 const base::Closure& error_callback) OVERRIDE { 523 std::vector<std::string> device_paths; 524 base::MessageLoopProxy::current()->PostTask( 525 FROM_HERE, base::Bind(callback, device_paths)); 526 } 527 528 virtual void EnumerateMountEntries( 529 const EnumerateMountEntriesCallback& callback, 530 const base::Closure& error_callback) OVERRIDE { 531 std::vector<MountEntry> entries; 532 base::MessageLoopProxy::current()->PostTask( 533 FROM_HERE, base::Bind(callback, entries)); 534 } 535 536 virtual void Format(const std::string& device_path, 537 const std::string& filesystem, 538 const base::Closure& callback, 539 const base::Closure& error_callback) OVERRIDE { 540 base::MessageLoopProxy::current()->PostTask(FROM_HERE, error_callback); 541 } 542 543 virtual void GetDeviceProperties( 544 const std::string& device_path, 545 const GetDevicePropertiesCallback& callback, 546 const base::Closure& error_callback) OVERRIDE { 547 base::MessageLoopProxy::current()->PostTask(FROM_HERE, error_callback); 548 } 549 550 virtual void SetMountEventHandler( 551 const MountEventHandler& mount_event_handler) OVERRIDE { 552 mount_event_handler_ = mount_event_handler; 553 } 554 555 virtual void SetMountCompletedHandler( 556 const MountCompletedHandler& mount_completed_handler) OVERRIDE { 557 mount_completed_handler_ = mount_completed_handler; 558 } 559 560 virtual void SetFormatCompletedHandler( 561 const FormatCompletedHandler& format_completed_handler) OVERRIDE { 562 format_completed_handler_ = format_completed_handler; 563 } 564 565 private: 566 // Performs file actions for Mount(). 567 static MountError PerformFakeMount(const std::string& source_path, 568 const base::FilePath& mounted_path) { 569 // Check the source path exists. 570 if (!base::PathExists(base::FilePath::FromUTF8Unsafe(source_path))) { 571 DLOG(ERROR) << "Source does not exist at " << source_path; 572 return MOUNT_ERROR_INVALID_PATH; 573 } 574 575 // Just create an empty directory and shows it as the mounted directory. 576 if (!base::CreateDirectory(mounted_path)) { 577 DLOG(ERROR) << "Failed to create directory at " << mounted_path.value(); 578 return MOUNT_ERROR_DIRECTORY_CREATION_FAILED; 579 } 580 581 // Put a dummy file. 582 const base::FilePath dummy_file_path = 583 mounted_path.Append("SUCCESSFULLY_PERFORMED_FAKE_MOUNT.txt"); 584 const std::string dummy_file_content = "This is a dummy file."; 585 const int write_result = base::WriteFile( 586 dummy_file_path, dummy_file_content.data(), dummy_file_content.size()); 587 if (write_result != static_cast<int>(dummy_file_content.size())) { 588 DLOG(ERROR) << "Failed to put a dummy file at " 589 << dummy_file_path.value(); 590 return MOUNT_ERROR_MOUNT_PROGRAM_FAILED; 591 } 592 593 return MOUNT_ERROR_NONE; 594 } 595 596 // Part of Mount() implementation. 597 void ContinueMount(const std::string& source_path, 598 MountType type, 599 const base::Closure& callback, 600 const base::FilePath& mounted_path, 601 MountError mount_error) { 602 if (mount_error != MOUNT_ERROR_NONE) { 603 FinishMount(mount_error, source_path, type, std::string(), callback); 604 return; 605 } 606 mounted_to_source_path_map_[mounted_path.value()] = source_path; 607 FinishMount(MOUNT_ERROR_NONE, source_path, type, 608 mounted_path.AsUTF8Unsafe(), callback); 609 } 610 611 // Runs |callback| and sends MountCompleted signal. 612 // Part of Mount() implementation. 613 void FinishMount(MountError error, 614 const std::string& source_path, 615 MountType type, 616 const std::string& mounted_path, 617 const base::Closure& callback) { 618 base::MessageLoopProxy::current()->PostTask(FROM_HERE, callback); 619 if (!mount_completed_handler_.is_null()) { 620 base::MessageLoopProxy::current()->PostTask( 621 FROM_HERE, 622 base::Bind(mount_completed_handler_, 623 MountEntry(error, source_path, type, mounted_path))); 624 } 625 } 626 627 // Mounted path to source path map. 628 std::map<std::string, std::string> mounted_to_source_path_map_; 629 630 MountEventHandler mount_event_handler_; 631 MountCompletedHandler mount_completed_handler_; 632 FormatCompletedHandler format_completed_handler_; 633 634 base::WeakPtrFactory<CrosDisksClientStubImpl> weak_ptr_factory_; 635 636 DISALLOW_COPY_AND_ASSIGN(CrosDisksClientStubImpl); 637 }; 638 639 } // namespace 640 641 //////////////////////////////////////////////////////////////////////////////// 642 // DiskInfo 643 644 DiskInfo::DiskInfo(const std::string& device_path, dbus::Response* response) 645 : device_path_(device_path), 646 is_drive_(false), 647 has_media_(false), 648 on_boot_device_(false), 649 on_removable_device_(false), 650 device_type_(DEVICE_TYPE_UNKNOWN), 651 total_size_in_bytes_(0), 652 is_read_only_(false), 653 is_hidden_(true) { 654 InitializeFromResponse(response); 655 } 656 657 DiskInfo::~DiskInfo() { 658 } 659 660 // Initializes |this| from |response| given by the cros-disks service. 661 // Below is an example of |response|'s raw message (long string is ellipsized). 662 // 663 // 664 // message_type: MESSAGE_METHOD_RETURN 665 // destination: :1.8 666 // sender: :1.16 667 // signature: a{sv} 668 // serial: 96 669 // reply_serial: 267 670 // 671 // array [ 672 // dict entry { 673 // string "DeviceFile" 674 // variant string "/dev/sdb" 675 // } 676 // dict entry { 677 // string "DeviceIsDrive" 678 // variant bool true 679 // } 680 // dict entry { 681 // string "DeviceIsMediaAvailable" 682 // variant bool true 683 // } 684 // dict entry { 685 // string "DeviceIsMounted" 686 // variant bool false 687 // } 688 // dict entry { 689 // string "DeviceIsOnBootDevice" 690 // variant bool false 691 // } 692 // dict entry { 693 // string "DeviceIsOnRemovableDevice" 694 // variant bool true 695 // } 696 // dict entry { 697 // string "DeviceIsReadOnly" 698 // variant bool false 699 // } 700 // dict entry { 701 // string "DeviceIsVirtual" 702 // variant bool false 703 // } 704 // dict entry { 705 // string "DeviceMediaType" 706 // variant uint32 1 707 // } 708 // dict entry { 709 // string "DeviceMountPaths" 710 // variant array [ 711 // ] 712 // } 713 // dict entry { 714 // string "DevicePresentationHide" 715 // variant bool true 716 // } 717 // dict entry { 718 // string "DeviceSize" 719 // variant uint64 7998537728 720 // } 721 // dict entry { 722 // string "DriveIsRotational" 723 // variant bool false 724 // } 725 // dict entry { 726 // string "VendorId" 727 // variant string "18d1" 728 // } 729 // dict entry { 730 // string "VendorName" 731 // variant string "Google Inc." 732 // } 733 // dict entry { 734 // string "ProductId" 735 // variant string "4e11" 736 // } 737 // dict entry { 738 // string "ProductName" 739 // variant string "Nexus One" 740 // } 741 // dict entry { 742 // string "DriveModel" 743 // variant string "TransMemory" 744 // } 745 // dict entry { 746 // string "IdLabel" 747 // variant string "" 748 // } 749 // dict entry { 750 // string "IdUuid" 751 // variant string "" 752 // } 753 // dict entry { 754 // string "NativePath" 755 // variant string "/sys/devices/pci0000:00/0000:00:1d.7/usb1/1-4/... 756 // } 757 // ] 758 void DiskInfo::InitializeFromResponse(dbus::Response* response) { 759 dbus::MessageReader reader(response); 760 scoped_ptr<base::Value> value(dbus::PopDataAsValue(&reader)); 761 base::DictionaryValue* properties = NULL; 762 if (!value || !value->GetAsDictionary(&properties)) 763 return; 764 765 properties->GetBooleanWithoutPathExpansion( 766 cros_disks::kDeviceIsDrive, &is_drive_); 767 properties->GetBooleanWithoutPathExpansion( 768 cros_disks::kDeviceIsReadOnly, &is_read_only_); 769 properties->GetBooleanWithoutPathExpansion( 770 cros_disks::kDevicePresentationHide, &is_hidden_); 771 properties->GetBooleanWithoutPathExpansion( 772 cros_disks::kDeviceIsMediaAvailable, &has_media_); 773 properties->GetBooleanWithoutPathExpansion( 774 cros_disks::kDeviceIsOnBootDevice, &on_boot_device_); 775 properties->GetBooleanWithoutPathExpansion( 776 cros_disks::kDeviceIsOnRemovableDevice, &on_removable_device_); 777 properties->GetStringWithoutPathExpansion( 778 cros_disks::kNativePath, &system_path_); 779 properties->GetStringWithoutPathExpansion( 780 cros_disks::kDeviceFile, &file_path_); 781 properties->GetStringWithoutPathExpansion(cros_disks::kVendorId, &vendor_id_); 782 properties->GetStringWithoutPathExpansion( 783 cros_disks::kVendorName, &vendor_name_); 784 properties->GetStringWithoutPathExpansion( 785 cros_disks::kProductId, &product_id_); 786 properties->GetStringWithoutPathExpansion( 787 cros_disks::kProductName, &product_name_); 788 properties->GetStringWithoutPathExpansion( 789 cros_disks::kDriveModel, &drive_model_); 790 properties->GetStringWithoutPathExpansion(cros_disks::kIdLabel, &label_); 791 properties->GetStringWithoutPathExpansion(cros_disks::kIdUuid, &uuid_); 792 793 // dbus::PopDataAsValue() pops uint64 as double. 794 // The top 11 bits of uint64 are dropped by the use of double. But, this works 795 // unless the size exceeds 8 PB. 796 double device_size_double = 0; 797 if (properties->GetDoubleWithoutPathExpansion(cros_disks::kDeviceSize, 798 &device_size_double)) 799 total_size_in_bytes_ = device_size_double; 800 801 // dbus::PopDataAsValue() pops uint32 as double. 802 double media_type_double = 0; 803 if (properties->GetDoubleWithoutPathExpansion(cros_disks::kDeviceMediaType, 804 &media_type_double)) 805 device_type_ = DeviceMediaTypeToDeviceType(media_type_double); 806 807 base::ListValue* mount_paths = NULL; 808 if (properties->GetListWithoutPathExpansion(cros_disks::kDeviceMountPaths, 809 &mount_paths)) 810 mount_paths->GetString(0, &mount_path_); 811 } 812 813 //////////////////////////////////////////////////////////////////////////////// 814 // CrosDisksClient 815 816 CrosDisksClient::CrosDisksClient() {} 817 818 CrosDisksClient::~CrosDisksClient() {} 819 820 // static 821 CrosDisksClient* CrosDisksClient::Create(DBusClientImplementationType type) { 822 if (type == REAL_DBUS_CLIENT_IMPLEMENTATION) 823 return new CrosDisksClientImpl(); 824 DCHECK_EQ(STUB_DBUS_CLIENT_IMPLEMENTATION, type); 825 return new CrosDisksClientStubImpl(); 826 } 827 828 // static 829 base::FilePath CrosDisksClient::GetArchiveMountPoint() { 830 return base::FilePath(base::SysInfo::IsRunningOnChromeOS() ? 831 FILE_PATH_LITERAL("/media/archive") : 832 FILE_PATH_LITERAL("/tmp/chromeos/media/archive")); 833 } 834 835 // static 836 base::FilePath CrosDisksClient::GetRemovableDiskMountPoint() { 837 return base::FilePath(base::SysInfo::IsRunningOnChromeOS() ? 838 FILE_PATH_LITERAL("/media/removable") : 839 FILE_PATH_LITERAL("/tmp/chromeos/media/removable")); 840 } 841 842 } // namespace chromeos 843