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
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
79bool 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.
96class 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.
458class 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
644DiskInfo::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
657DiskInfo::~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// ]
758void 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
816CrosDisksClient::CrosDisksClient() {}
817
818CrosDisksClient::~CrosDisksClient() {}
819
820// static
821CrosDisksClient* 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
829base::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
836base::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