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/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