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
27namespace chromeos {
28
29namespace {
30
31const char* kDefaultMountOptions[] = {
32  "rw",
33  "nodev",
34  "noexec",
35  "nosuid",
36};
37
38const char* kDefaultUnmountOptions[] = {
39  "force",
40};
41
42const char kLazyUnmountOption[] = "lazy";
43
44const char kMountLabelOption[] = "mountlabel";
45
46// Checks if retrieved media type is in boundaries of DeviceMediaType.
47bool 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.
54DeviceType 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.
80class 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.
358class 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
526DiskInfo::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
538DiskInfo::~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// ]
635void 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
691CrosDisksClient::CrosDisksClient() {}
692
693CrosDisksClient::~CrosDisksClient() {}
694
695// static
696CrosDisksClient* 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
705base::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
712base::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