Home | History | Annotate | Download | only in dbus
      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/chromeos/chromeos_version.h"
     11 #include "base/file_util.h"
     12 #include "base/files/file_path.h"
     13 #include "base/location.h"
     14 #include "base/message_loop/message_loop_proxy.h"
     15 #include "base/stl_util.h"
     16 #include "base/strings/stringprintf.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 // The CrosDisksClient implementation.
     80 class CrosDisksClientImpl : public CrosDisksClient {
     81  public:
     82   explicit CrosDisksClientImpl(dbus::Bus* bus)
     83       : proxy_(bus->GetObjectProxy(
     84           cros_disks::kCrosDisksServiceName,
     85           dbus::ObjectPath(cros_disks::kCrosDisksServicePath))),
     86         weak_ptr_factory_(this) {
     87   }
     88 
     89   // CrosDisksClient override.
     90   virtual void Mount(const std::string& source_path,
     91                      const std::string& source_format,
     92                      const std::string& mount_label,
     93                      const base::Closure& callback,
     94                      const base::Closure& error_callback) OVERRIDE {
     95     dbus::MethodCall method_call(cros_disks::kCrosDisksInterface,
     96                                  cros_disks::kMount);
     97     dbus::MessageWriter writer(&method_call);
     98     writer.AppendString(source_path);
     99     writer.AppendString(source_format);
    100     std::vector<std::string> mount_options(kDefaultMountOptions,
    101                                            kDefaultMountOptions +
    102                                            arraysize(kDefaultMountOptions));
    103     if (!mount_label.empty()) {
    104       std::string mount_label_option = base::StringPrintf("%s=%s",
    105                                                           kMountLabelOption,
    106                                                           mount_label.c_str());
    107       mount_options.push_back(mount_label_option);
    108     }
    109     writer.AppendArrayOfStrings(mount_options);
    110     proxy_->CallMethod(&method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
    111                        base::Bind(&CrosDisksClientImpl::OnMount,
    112                                   weak_ptr_factory_.GetWeakPtr(),
    113                                   callback,
    114                                   error_callback));
    115   }
    116 
    117   // CrosDisksClient override.
    118   virtual void Unmount(const std::string& device_path,
    119                        UnmountOptions options,
    120                        const base::Closure& callback,
    121                        const base::Closure& error_callback) OVERRIDE {
    122     dbus::MethodCall method_call(cros_disks::kCrosDisksInterface,
    123                                  cros_disks::kUnmount);
    124     dbus::MessageWriter writer(&method_call);
    125     writer.AppendString(device_path);
    126 
    127     std::vector<std::string> unmount_options(
    128         kDefaultUnmountOptions,
    129         kDefaultUnmountOptions + arraysize(kDefaultUnmountOptions));
    130     if (options == UNMOUNT_OPTIONS_LAZY)
    131       unmount_options.push_back(kLazyUnmountOption);
    132 
    133     writer.AppendArrayOfStrings(unmount_options);
    134     proxy_->CallMethod(&method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
    135                        base::Bind(&CrosDisksClientImpl::OnUnmount,
    136                                   weak_ptr_factory_.GetWeakPtr(),
    137                                   callback,
    138                                   error_callback));
    139   }
    140 
    141   // CrosDisksClient override.
    142   virtual void EnumerateAutoMountableDevices(
    143       const EnumerateAutoMountableDevicesCallback& callback,
    144       const base::Closure& error_callback) OVERRIDE {
    145     dbus::MethodCall method_call(cros_disks::kCrosDisksInterface,
    146                                  cros_disks::kEnumerateAutoMountableDevices);
    147     proxy_->CallMethod(
    148         &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
    149         base::Bind(&CrosDisksClientImpl::OnEnumerateAutoMountableDevices,
    150                    weak_ptr_factory_.GetWeakPtr(),
    151                    callback,
    152                    error_callback));
    153   }
    154 
    155   // CrosDisksClient override.
    156   virtual void FormatDevice(const std::string& device_path,
    157                             const std::string& filesystem,
    158                             const FormatDeviceCallback& callback,
    159                             const base::Closure& error_callback) OVERRIDE {
    160     dbus::MethodCall method_call(cros_disks::kCrosDisksInterface,
    161                                  cros_disks::kFormatDevice);
    162     dbus::MessageWriter writer(&method_call);
    163     writer.AppendString(device_path);
    164     writer.AppendString(filesystem);
    165     proxy_->CallMethod(&method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
    166                        base::Bind(&CrosDisksClientImpl::OnFormatDevice,
    167                                   weak_ptr_factory_.GetWeakPtr(),
    168                                   callback,
    169                                   error_callback));
    170   }
    171 
    172   // CrosDisksClient override.
    173   virtual void GetDeviceProperties(
    174       const std::string& device_path,
    175       const GetDevicePropertiesCallback& callback,
    176       const base::Closure& error_callback) OVERRIDE {
    177     dbus::MethodCall method_call(cros_disks::kCrosDisksInterface,
    178                                  cros_disks::kGetDeviceProperties);
    179     dbus::MessageWriter writer(&method_call);
    180     writer.AppendString(device_path);
    181     proxy_->CallMethod(&method_call,
    182                        dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
    183                        base::Bind(&CrosDisksClientImpl::OnGetDeviceProperties,
    184                                   weak_ptr_factory_.GetWeakPtr(),
    185                                   device_path,
    186                                   callback,
    187                                   error_callback));
    188   }
    189 
    190   // CrosDisksClient override.
    191   virtual void SetUpConnections(
    192       const MountEventHandler& mount_event_handler,
    193       const MountCompletedHandler& mount_completed_handler) OVERRIDE {
    194     static const SignalEventTuple kSignalEventTuples[] = {
    195       { cros_disks::kDeviceAdded, CROS_DISKS_DEVICE_ADDED },
    196       { cros_disks::kDeviceScanned, CROS_DISKS_DEVICE_SCANNED },
    197       { cros_disks::kDeviceRemoved, CROS_DISKS_DEVICE_REMOVED },
    198       { cros_disks::kDiskAdded, CROS_DISKS_DISK_ADDED },
    199       { cros_disks::kDiskChanged, CROS_DISKS_DISK_CHANGED },
    200       { cros_disks::kDiskRemoved, CROS_DISKS_DISK_REMOVED },
    201       { cros_disks::kFormattingFinished, CROS_DISKS_FORMATTING_FINISHED },
    202     };
    203     const size_t kNumSignalEventTuples = arraysize(kSignalEventTuples);
    204 
    205     for (size_t i = 0; i < kNumSignalEventTuples; ++i) {
    206       proxy_->ConnectToSignal(
    207           cros_disks::kCrosDisksInterface,
    208           kSignalEventTuples[i].signal_name,
    209           base::Bind(&CrosDisksClientImpl::OnMountEvent,
    210                      weak_ptr_factory_.GetWeakPtr(),
    211                      kSignalEventTuples[i].event_type,
    212                      mount_event_handler),
    213           base::Bind(&CrosDisksClientImpl::OnSignalConnected,
    214                      weak_ptr_factory_.GetWeakPtr()));
    215     }
    216     proxy_->ConnectToSignal(
    217         cros_disks::kCrosDisksInterface,
    218         cros_disks::kMountCompleted,
    219         base::Bind(&CrosDisksClientImpl::OnMountCompleted,
    220                    weak_ptr_factory_.GetWeakPtr(),
    221                    mount_completed_handler),
    222         base::Bind(&CrosDisksClientImpl::OnSignalConnected,
    223                    weak_ptr_factory_.GetWeakPtr()));
    224   }
    225 
    226  private:
    227   // A struct to contain a pair of signal name and mount event type.
    228   // Used by SetUpConnections.
    229   struct SignalEventTuple {
    230     const char *signal_name;
    231     MountEventType event_type;
    232   };
    233 
    234   // Handles the result of Mount and calls |callback| or |error_callback|.
    235   void OnMount(const base::Closure& callback,
    236                const base::Closure& error_callback,
    237                dbus::Response* response) {
    238     if (!response) {
    239       error_callback.Run();
    240       return;
    241     }
    242     callback.Run();
    243   }
    244 
    245   // Handles the result of Unount and calls |callback| or |error_callback|.
    246   void OnUnmount(const base::Closure& callback,
    247                  const base::Closure& error_callback,
    248                  dbus::Response* response) {
    249     if (!response) {
    250       error_callback.Run();
    251       return;
    252     }
    253     callback.Run();
    254   }
    255 
    256   // Handles the result of EnumerateAutoMountableDevices and calls |callback| or
    257   // |error_callback|.
    258   void OnEnumerateAutoMountableDevices(
    259       const EnumerateAutoMountableDevicesCallback& callback,
    260       const base::Closure& error_callback,
    261       dbus::Response* response) {
    262     if (!response) {
    263       error_callback.Run();
    264       return;
    265     }
    266     dbus::MessageReader reader(response);
    267     std::vector<std::string> device_paths;
    268     if (!reader.PopArrayOfStrings(&device_paths)) {
    269       LOG(ERROR) << "Invalid response: " << response->ToString();
    270       error_callback.Run();
    271       return;
    272     }
    273     callback.Run(device_paths);
    274   }
    275 
    276   // Handles the result of FormatDevice and calls |callback| or
    277   // |error_callback|.
    278   void OnFormatDevice(const FormatDeviceCallback& callback,
    279                       const base::Closure& error_callback,
    280                       dbus::Response* response) {
    281     if (!response) {
    282       error_callback.Run();
    283       return;
    284     }
    285     dbus::MessageReader reader(response);
    286     bool success = false;
    287     if (!reader.PopBool(&success)) {
    288       LOG(ERROR) << "Invalid response: " << response->ToString();
    289       error_callback.Run();
    290       return;
    291     }
    292     callback.Run(success);
    293   }
    294 
    295   // Handles the result of GetDeviceProperties and calls |callback| or
    296   // |error_callback|.
    297   void OnGetDeviceProperties(const std::string& device_path,
    298                              const GetDevicePropertiesCallback& callback,
    299                              const base::Closure& error_callback,
    300                              dbus::Response* response) {
    301     if (!response) {
    302       error_callback.Run();
    303       return;
    304     }
    305     DiskInfo disk(device_path, response);
    306     callback.Run(disk);
    307   }
    308 
    309   // Handles mount event signals and calls |handler|.
    310   void OnMountEvent(MountEventType event_type,
    311                     MountEventHandler handler,
    312                     dbus::Signal* signal) {
    313     dbus::MessageReader reader(signal);
    314     std::string device;
    315     if (!reader.PopString(&device)) {
    316       LOG(ERROR) << "Invalid signal: " << signal->ToString();
    317       return;
    318     }
    319     handler.Run(event_type, device);
    320   }
    321 
    322   // Handles MountCompleted signal and calls |handler|.
    323   void OnMountCompleted(MountCompletedHandler handler, dbus::Signal* signal) {
    324     dbus::MessageReader reader(signal);
    325     unsigned int error_code = 0;
    326     std::string source_path;
    327     unsigned int mount_type = 0;
    328     std::string mount_path;
    329     if (!reader.PopUint32(&error_code) ||
    330         !reader.PopString(&source_path) ||
    331         !reader.PopUint32(&mount_type) ||
    332         !reader.PopString(&mount_path)) {
    333       LOG(ERROR) << "Invalid signal: " << signal->ToString();
    334       return;
    335     }
    336     handler.Run(static_cast<MountError>(error_code), source_path,
    337                 static_cast<MountType>(mount_type), mount_path);
    338   }
    339 
    340   // Handles the result of signal connection setup.
    341   void OnSignalConnected(const std::string& interface,
    342                          const std::string& signal,
    343                          bool succeeded) {
    344     LOG_IF(ERROR, !succeeded) << "Connect to " << interface << " " <<
    345         signal << " failed.";
    346   }
    347 
    348   dbus::ObjectProxy* proxy_;
    349 
    350   // Note: This should remain the last member so it'll be destroyed and
    351   // invalidate its weak pointers before any other members are destroyed.
    352   base::WeakPtrFactory<CrosDisksClientImpl> weak_ptr_factory_;
    353 
    354   DISALLOW_COPY_AND_ASSIGN(CrosDisksClientImpl);
    355 };
    356 
    357 // A stub implementaion of CrosDisksClient.
    358 class CrosDisksClientStubImpl : public CrosDisksClient {
    359  public:
    360   CrosDisksClientStubImpl()
    361       : weak_ptr_factory_(this) {}
    362 
    363   virtual ~CrosDisksClientStubImpl() {}
    364 
    365   // CrosDisksClient overrides:
    366   virtual void Mount(const std::string& source_path,
    367                      const std::string& source_format,
    368                      const std::string& mount_label,
    369                      const base::Closure& callback,
    370                      const base::Closure& error_callback) OVERRIDE {
    371     // This stub implementation only accepts archive mount requests.
    372     const MountType type = MOUNT_TYPE_ARCHIVE;
    373 
    374     const base::FilePath mounted_path = GetArchiveMountPoint().Append(
    375         base::FilePath::FromUTF8Unsafe(mount_label));
    376 
    377     // Already mounted path.
    378     if (mounted_to_source_path_map_.count(mounted_path.value()) != 0) {
    379       FinishMount(MOUNT_ERROR_PATH_ALREADY_MOUNTED, source_path, type,
    380                   std::string(), callback);
    381       return;
    382     }
    383 
    384     // Perform fake mount.
    385     base::PostTaskAndReplyWithResult(
    386         base::WorkerPool::GetTaskRunner(true /* task_is_slow */).get(),
    387         FROM_HERE,
    388         base::Bind(&PerformFakeMount, source_path, mounted_path),
    389         base::Bind(&CrosDisksClientStubImpl::ContinueMount,
    390                    weak_ptr_factory_.GetWeakPtr(),
    391                    source_path,
    392                    type,
    393                    callback,
    394                    mounted_path));
    395   }
    396 
    397   virtual void Unmount(const std::string& device_path,
    398                        UnmountOptions options,
    399                        const base::Closure& callback,
    400                        const base::Closure& error_callback) OVERRIDE {
    401     // Not mounted.
    402     if (mounted_to_source_path_map_.count(device_path) == 0) {
    403       base::MessageLoopProxy::current()->PostTask(FROM_HERE, error_callback);
    404       return;
    405     }
    406 
    407     mounted_to_source_path_map_.erase(device_path);
    408 
    409     // Remove the directory created in Mount().
    410     base::WorkerPool::PostTaskAndReply(
    411         FROM_HERE,
    412         base::Bind(base::IgnoreResult(&base::DeleteFile),
    413                    base::FilePath::FromUTF8Unsafe(device_path),
    414                    true /* recursive */),
    415         callback,
    416         true /* task_is_slow */);
    417   }
    418 
    419   virtual void EnumerateAutoMountableDevices(
    420       const EnumerateAutoMountableDevicesCallback& callback,
    421       const base::Closure& error_callback) OVERRIDE {
    422     std::vector<std::string> device_paths;
    423     base::MessageLoopProxy::current()->PostTask(
    424         FROM_HERE, base::Bind(callback, device_paths));
    425   }
    426 
    427   virtual void FormatDevice(const std::string& device_path,
    428                             const std::string& filesystem,
    429                             const FormatDeviceCallback& callback,
    430                             const base::Closure& error_callback) OVERRIDE {
    431     base::MessageLoopProxy::current()->PostTask(FROM_HERE, error_callback);
    432   }
    433 
    434   virtual void GetDeviceProperties(
    435       const std::string& device_path,
    436       const GetDevicePropertiesCallback& callback,
    437       const base::Closure& error_callback) OVERRIDE {
    438     base::MessageLoopProxy::current()->PostTask(FROM_HERE, error_callback);
    439   }
    440 
    441   virtual void SetUpConnections(
    442       const MountEventHandler& mount_event_handler,
    443       const MountCompletedHandler& mount_completed_handler) OVERRIDE {
    444     mount_event_handler_ = mount_event_handler;
    445     mount_completed_handler_ = mount_completed_handler;
    446   }
    447 
    448  private:
    449   // Performs file actions for Mount().
    450   static MountError PerformFakeMount(const std::string& source_path,
    451                                      const base::FilePath& mounted_path) {
    452     // Check the source path exists.
    453     if (!base::PathExists(base::FilePath::FromUTF8Unsafe(source_path))) {
    454       DLOG(ERROR) << "Source does not exist at " << source_path;
    455       return MOUNT_ERROR_INVALID_PATH;
    456     }
    457 
    458     // Just create an empty directory and shows it as the mounted directory.
    459     if (!file_util::CreateDirectory(mounted_path)) {
    460       DLOG(ERROR) << "Failed to create directory at " << mounted_path.value();
    461       return MOUNT_ERROR_DIRECTORY_CREATION_FAILED;
    462     }
    463 
    464     // Put a dummy file.
    465     const base::FilePath dummy_file_path =
    466         mounted_path.Append("SUCCESSFULLY_PERFORMED_FAKE_MOUNT.txt");
    467     const std::string dummy_file_content = "This is a dummy file.";
    468     const int write_result = file_util::WriteFile(
    469         dummy_file_path, dummy_file_content.data(), dummy_file_content.size());
    470     if (write_result != static_cast<int>(dummy_file_content.size())) {
    471       DLOG(ERROR) << "Failed to put a dummy file at "
    472                   << dummy_file_path.value();
    473       return MOUNT_ERROR_MOUNT_PROGRAM_FAILED;
    474     }
    475 
    476     return MOUNT_ERROR_NONE;
    477   }
    478 
    479   // Part of Mount() implementation.
    480   void ContinueMount(const std::string& source_path,
    481                      MountType type,
    482                      const base::Closure& callback,
    483                      const base::FilePath& mounted_path,
    484                      MountError mount_error) {
    485     if (mount_error != MOUNT_ERROR_NONE) {
    486       FinishMount(mount_error, source_path, type, std::string(), callback);
    487       return;
    488     }
    489     mounted_to_source_path_map_[mounted_path.value()] = source_path;
    490     FinishMount(MOUNT_ERROR_NONE, source_path, type,
    491                 mounted_path.AsUTF8Unsafe(), callback);
    492   }
    493 
    494   // Runs |callback| and sends MountCompleted signal.
    495   // Part of Mount() implementation.
    496   void FinishMount(MountError error,
    497                    const std::string& source_path,
    498                    MountType type,
    499                    const std::string& mounted_path,
    500                    const base::Closure& callback) {
    501     base::MessageLoopProxy::current()->PostTask(FROM_HERE, callback);
    502     if (!mount_completed_handler_.is_null()) {
    503       base::MessageLoopProxy::current()->PostTask(
    504           FROM_HERE,
    505           base::Bind(mount_completed_handler_,
    506                      error, source_path, type, mounted_path));
    507     }
    508   }
    509 
    510   // Mounted path to source path map.
    511   std::map<std::string, std::string> mounted_to_source_path_map_;
    512 
    513   MountEventHandler mount_event_handler_;
    514   MountCompletedHandler mount_completed_handler_;
    515 
    516   base::WeakPtrFactory<CrosDisksClientStubImpl> weak_ptr_factory_;
    517 
    518   DISALLOW_COPY_AND_ASSIGN(CrosDisksClientStubImpl);
    519 };
    520 
    521 }  // namespace
    522 
    523 ////////////////////////////////////////////////////////////////////////////////
    524 // DiskInfo
    525 
    526 DiskInfo::DiskInfo(const std::string& device_path, dbus::Response* response)
    527     : device_path_(device_path),
    528       is_drive_(false),
    529       has_media_(false),
    530       on_boot_device_(false),
    531       device_type_(DEVICE_TYPE_UNKNOWN),
    532       total_size_in_bytes_(0),
    533       is_read_only_(false),
    534       is_hidden_(true) {
    535   InitializeFromResponse(response);
    536 }
    537 
    538 DiskInfo::~DiskInfo() {
    539 }
    540 
    541 // Initializes |this| from |response| given by the cros-disks service.
    542 // Below is an example of |response|'s raw message (long string is ellipsized).
    543 //
    544 //
    545 // message_type: MESSAGE_METHOD_RETURN
    546 // destination: :1.8
    547 // sender: :1.16
    548 // signature: a{sv}
    549 // serial: 96
    550 // reply_serial: 267
    551 //
    552 // array [
    553 //   dict entry {
    554 //     string "DeviceFile"
    555 //     variant       string "/dev/sdb"
    556 //   }
    557 //   dict entry {
    558 //     string "DeviceIsDrive"
    559 //     variant       bool true
    560 //   }
    561 //   dict entry {
    562 //     string "DeviceIsMediaAvailable"
    563 //     variant       bool true
    564 //   }
    565 //   dict entry {
    566 //     string "DeviceIsMounted"
    567 //     variant       bool false
    568 //   }
    569 //   dict entry {
    570 //     string "DeviceIsOnBootDevice"
    571 //     variant       bool false
    572 //   }
    573 //   dict entry {
    574 //     string "DeviceIsReadOnly"
    575 //     variant       bool false
    576 //   }
    577 //   dict entry {
    578 //     string "DeviceIsVirtual"
    579 //     variant       bool false
    580 //   }
    581 //   dict entry {
    582 //     string "DeviceMediaType"
    583 //     variant       uint32 1
    584 //   }
    585 //   dict entry {
    586 //     string "DeviceMountPaths"
    587 //     variant       array [
    588 //       ]
    589 //   }
    590 //   dict entry {
    591 //     string "DevicePresentationHide"
    592 //     variant       bool true
    593 //   }
    594 //   dict entry {
    595 //     string "DeviceSize"
    596 //     variant       uint64 7998537728
    597 //   }
    598 //   dict entry {
    599 //     string "DriveIsRotational"
    600 //     variant       bool false
    601 //   }
    602 //   dict entry {
    603 //     string "VendorId"
    604 //     variant       string "18d1"
    605 //   }
    606 //   dict entry {
    607 //     string "VendorName"
    608 //     variant       string "Google Inc."
    609 //   }
    610 //   dict entry {
    611 //     string "ProductId"
    612 //     variant       string "4e11"
    613 //   }
    614 //   dict entry {
    615 //     string "ProductName"
    616 //     variant       string "Nexus One"
    617 //   }
    618 //   dict entry {
    619 //     string "DriveModel"
    620 //     variant       string "TransMemory"
    621 //   }
    622 //   dict entry {
    623 //     string "IdLabel"
    624 //     variant       string ""
    625 //   }
    626 //   dict entry {
    627 //     string "IdUuid"
    628 //     variant       string ""
    629 //   }
    630 //   dict entry {
    631 //     string "NativePath"
    632 //     variant       string "/sys/devices/pci0000:00/0000:00:1d.7/usb1/1-4/...
    633 //   }
    634 // ]
    635 void DiskInfo::InitializeFromResponse(dbus::Response* response) {
    636   dbus::MessageReader reader(response);
    637   scoped_ptr<base::Value> value(dbus::PopDataAsValue(&reader));
    638   base::DictionaryValue* properties = NULL;
    639   if (!value || !value->GetAsDictionary(&properties))
    640     return;
    641 
    642   properties->GetBooleanWithoutPathExpansion(
    643       cros_disks::kDeviceIsDrive, &is_drive_);
    644   properties->GetBooleanWithoutPathExpansion(
    645       cros_disks::kDeviceIsReadOnly, &is_read_only_);
    646   properties->GetBooleanWithoutPathExpansion(
    647       cros_disks::kDevicePresentationHide, &is_hidden_);
    648   properties->GetBooleanWithoutPathExpansion(
    649       cros_disks::kDeviceIsMediaAvailable, &has_media_);
    650   properties->GetBooleanWithoutPathExpansion(
    651       cros_disks::kDeviceIsOnBootDevice, &on_boot_device_);
    652   properties->GetStringWithoutPathExpansion(
    653       cros_disks::kNativePath, &system_path_);
    654   properties->GetStringWithoutPathExpansion(
    655       cros_disks::kDeviceFile, &file_path_);
    656   properties->GetStringWithoutPathExpansion(cros_disks::kVendorId, &vendor_id_);
    657   properties->GetStringWithoutPathExpansion(
    658       cros_disks::kVendorName, &vendor_name_);
    659   properties->GetStringWithoutPathExpansion(
    660       cros_disks::kProductId, &product_id_);
    661   properties->GetStringWithoutPathExpansion(
    662       cros_disks::kProductName, &product_name_);
    663   properties->GetStringWithoutPathExpansion(
    664       cros_disks::kDriveModel, &drive_model_);
    665   properties->GetStringWithoutPathExpansion(cros_disks::kIdLabel, &label_);
    666   properties->GetStringWithoutPathExpansion(cros_disks::kIdUuid, &uuid_);
    667 
    668   // dbus::PopDataAsValue() pops uint64 as double.
    669   // The top 11 bits of uint64 are dropped by the use of double. But, this works
    670   // unless the size exceeds 8 PB.
    671   double device_size_double = 0;
    672   if (properties->GetDoubleWithoutPathExpansion(cros_disks::kDeviceSize,
    673                                                 &device_size_double))
    674     total_size_in_bytes_ = device_size_double;
    675 
    676   // dbus::PopDataAsValue() pops uint32 as double.
    677   double media_type_double = 0;
    678   if (properties->GetDoubleWithoutPathExpansion(cros_disks::kDeviceMediaType,
    679                                                 &media_type_double))
    680     device_type_ = DeviceMediaTypeToDeviceType(media_type_double);
    681 
    682   base::ListValue* mount_paths = NULL;
    683   if (properties->GetListWithoutPathExpansion(cros_disks::kDeviceMountPaths,
    684                                               &mount_paths))
    685     mount_paths->GetString(0, &mount_path_);
    686 }
    687 
    688 ////////////////////////////////////////////////////////////////////////////////
    689 // CrosDisksClient
    690 
    691 CrosDisksClient::CrosDisksClient() {}
    692 
    693 CrosDisksClient::~CrosDisksClient() {}
    694 
    695 // static
    696 CrosDisksClient* CrosDisksClient::Create(DBusClientImplementationType type,
    697                                          dbus::Bus* bus) {
    698   if (type == REAL_DBUS_CLIENT_IMPLEMENTATION)
    699     return new CrosDisksClientImpl(bus);
    700   DCHECK_EQ(STUB_DBUS_CLIENT_IMPLEMENTATION, type);
    701   return new CrosDisksClientStubImpl();
    702 }
    703 
    704 // static
    705 base::FilePath CrosDisksClient::GetArchiveMountPoint() {
    706   return base::FilePath(base::chromeos::IsRunningOnChromeOS() ?
    707                         FILE_PATH_LITERAL("/media/archive") :
    708                         FILE_PATH_LITERAL("/tmp/chromeos/media/archive"));
    709 }
    710 
    711 // static
    712 base::FilePath CrosDisksClient::GetRemovableDiskMountPoint() {
    713   return base::FilePath(base::chromeos::IsRunningOnChromeOS() ?
    714                         FILE_PATH_LITERAL("/media/removable") :
    715                         FILE_PATH_LITERAL("/tmp/chromeos/media/removable"));
    716 }
    717 
    718 }  // namespace chromeos
    719