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