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/file_util.h" 11 #include "base/files/file_path.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 device_type_(DEVICE_TYPE_UNKNOWN), 650 total_size_in_bytes_(0), 651 is_read_only_(false), 652 is_hidden_(true) { 653 InitializeFromResponse(response); 654 } 655 656 DiskInfo::~DiskInfo() { 657 } 658 659 // Initializes |this| from |response| given by the cros-disks service. 660 // Below is an example of |response|'s raw message (long string is ellipsized). 661 // 662 // 663 // message_type: MESSAGE_METHOD_RETURN 664 // destination: :1.8 665 // sender: :1.16 666 // signature: a{sv} 667 // serial: 96 668 // reply_serial: 267 669 // 670 // array [ 671 // dict entry { 672 // string "DeviceFile" 673 // variant string "/dev/sdb" 674 // } 675 // dict entry { 676 // string "DeviceIsDrive" 677 // variant bool true 678 // } 679 // dict entry { 680 // string "DeviceIsMediaAvailable" 681 // variant bool true 682 // } 683 // dict entry { 684 // string "DeviceIsMounted" 685 // variant bool false 686 // } 687 // dict entry { 688 // string "DeviceIsOnBootDevice" 689 // variant bool false 690 // } 691 // dict entry { 692 // string "DeviceIsReadOnly" 693 // variant bool false 694 // } 695 // dict entry { 696 // string "DeviceIsVirtual" 697 // variant bool false 698 // } 699 // dict entry { 700 // string "DeviceMediaType" 701 // variant uint32 1 702 // } 703 // dict entry { 704 // string "DeviceMountPaths" 705 // variant array [ 706 // ] 707 // } 708 // dict entry { 709 // string "DevicePresentationHide" 710 // variant bool true 711 // } 712 // dict entry { 713 // string "DeviceSize" 714 // variant uint64 7998537728 715 // } 716 // dict entry { 717 // string "DriveIsRotational" 718 // variant bool false 719 // } 720 // dict entry { 721 // string "VendorId" 722 // variant string "18d1" 723 // } 724 // dict entry { 725 // string "VendorName" 726 // variant string "Google Inc." 727 // } 728 // dict entry { 729 // string "ProductId" 730 // variant string "4e11" 731 // } 732 // dict entry { 733 // string "ProductName" 734 // variant string "Nexus One" 735 // } 736 // dict entry { 737 // string "DriveModel" 738 // variant string "TransMemory" 739 // } 740 // dict entry { 741 // string "IdLabel" 742 // variant string "" 743 // } 744 // dict entry { 745 // string "IdUuid" 746 // variant string "" 747 // } 748 // dict entry { 749 // string "NativePath" 750 // variant string "/sys/devices/pci0000:00/0000:00:1d.7/usb1/1-4/... 751 // } 752 // ] 753 void DiskInfo::InitializeFromResponse(dbus::Response* response) { 754 dbus::MessageReader reader(response); 755 scoped_ptr<base::Value> value(dbus::PopDataAsValue(&reader)); 756 base::DictionaryValue* properties = NULL; 757 if (!value || !value->GetAsDictionary(&properties)) 758 return; 759 760 properties->GetBooleanWithoutPathExpansion( 761 cros_disks::kDeviceIsDrive, &is_drive_); 762 properties->GetBooleanWithoutPathExpansion( 763 cros_disks::kDeviceIsReadOnly, &is_read_only_); 764 properties->GetBooleanWithoutPathExpansion( 765 cros_disks::kDevicePresentationHide, &is_hidden_); 766 properties->GetBooleanWithoutPathExpansion( 767 cros_disks::kDeviceIsMediaAvailable, &has_media_); 768 properties->GetBooleanWithoutPathExpansion( 769 cros_disks::kDeviceIsOnBootDevice, &on_boot_device_); 770 properties->GetStringWithoutPathExpansion( 771 cros_disks::kNativePath, &system_path_); 772 properties->GetStringWithoutPathExpansion( 773 cros_disks::kDeviceFile, &file_path_); 774 properties->GetStringWithoutPathExpansion(cros_disks::kVendorId, &vendor_id_); 775 properties->GetStringWithoutPathExpansion( 776 cros_disks::kVendorName, &vendor_name_); 777 properties->GetStringWithoutPathExpansion( 778 cros_disks::kProductId, &product_id_); 779 properties->GetStringWithoutPathExpansion( 780 cros_disks::kProductName, &product_name_); 781 properties->GetStringWithoutPathExpansion( 782 cros_disks::kDriveModel, &drive_model_); 783 properties->GetStringWithoutPathExpansion(cros_disks::kIdLabel, &label_); 784 properties->GetStringWithoutPathExpansion(cros_disks::kIdUuid, &uuid_); 785 786 // dbus::PopDataAsValue() pops uint64 as double. 787 // The top 11 bits of uint64 are dropped by the use of double. But, this works 788 // unless the size exceeds 8 PB. 789 double device_size_double = 0; 790 if (properties->GetDoubleWithoutPathExpansion(cros_disks::kDeviceSize, 791 &device_size_double)) 792 total_size_in_bytes_ = device_size_double; 793 794 // dbus::PopDataAsValue() pops uint32 as double. 795 double media_type_double = 0; 796 if (properties->GetDoubleWithoutPathExpansion(cros_disks::kDeviceMediaType, 797 &media_type_double)) 798 device_type_ = DeviceMediaTypeToDeviceType(media_type_double); 799 800 base::ListValue* mount_paths = NULL; 801 if (properties->GetListWithoutPathExpansion(cros_disks::kDeviceMountPaths, 802 &mount_paths)) 803 mount_paths->GetString(0, &mount_path_); 804 } 805 806 //////////////////////////////////////////////////////////////////////////////// 807 // CrosDisksClient 808 809 CrosDisksClient::CrosDisksClient() {} 810 811 CrosDisksClient::~CrosDisksClient() {} 812 813 // static 814 CrosDisksClient* CrosDisksClient::Create(DBusClientImplementationType type) { 815 if (type == REAL_DBUS_CLIENT_IMPLEMENTATION) 816 return new CrosDisksClientImpl(); 817 DCHECK_EQ(STUB_DBUS_CLIENT_IMPLEMENTATION, type); 818 return new CrosDisksClientStubImpl(); 819 } 820 821 // static 822 base::FilePath CrosDisksClient::GetArchiveMountPoint() { 823 return base::FilePath(base::SysInfo::IsRunningOnChromeOS() ? 824 FILE_PATH_LITERAL("/media/archive") : 825 FILE_PATH_LITERAL("/tmp/chromeos/media/archive")); 826 } 827 828 // static 829 base::FilePath CrosDisksClient::GetRemovableDiskMountPoint() { 830 return base::FilePath(base::SysInfo::IsRunningOnChromeOS() ? 831 FILE_PATH_LITERAL("/media/removable") : 832 FILE_PATH_LITERAL("/tmp/chromeos/media/removable")); 833 } 834 835 } // namespace chromeos 836