Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / chromeos / dbus / cros_disks_client.cc
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "chromeos/dbus/cros_disks_client.h"
6
7 #include <map>
8
9 #include "base/bind.h"
10 #include "base/file_util.h"
11 #include "base/files/file_path.h"
12 #include "base/location.h"
13 #include "base/message_loop/message_loop_proxy.h"
14 #include "base/stl_util.h"
15 #include "base/strings/stringprintf.h"
16 #include "base/sys_info.h"
17 #include "base/task_runner_util.h"
18 #include "base/threading/worker_pool.h"
19 #include "base/values.h"
20 #include "dbus/bus.h"
21 #include "dbus/message.h"
22 #include "dbus/object_path.h"
23 #include "dbus/object_proxy.h"
24 #include "dbus/values_util.h"
25 #include "third_party/cros_system_api/dbus/service_constants.h"
26
27 namespace chromeos {
28
29 namespace {
30
31 const char* kDefaultMountOptions[] = {
32   "rw",
33   "nodev",
34   "noexec",
35   "nosuid",
36 };
37
38 const char* kDefaultUnmountOptions[] = {
39   "force",
40 };
41
42 const char kLazyUnmountOption[] = "lazy";
43
44 const char kMountLabelOption[] = "mountlabel";
45
46 // Checks if retrieved media type is in boundaries of DeviceMediaType.
47 bool IsValidMediaType(uint32 type) {
48   return type < static_cast<uint32>(cros_disks::DEVICE_MEDIA_NUM_VALUES);
49 }
50
51 // Translates enum used in cros-disks to enum used in Chrome.
52 // Note that we could just do static_cast, but this is less sensitive to
53 // changes in cros-disks.
54 DeviceType DeviceMediaTypeToDeviceType(uint32 media_type_uint32) {
55   if (!IsValidMediaType(media_type_uint32))
56     return DEVICE_TYPE_UNKNOWN;
57
58   cros_disks::DeviceMediaType media_type =
59       cros_disks::DeviceMediaType(media_type_uint32);
60
61   switch (media_type) {
62     case(cros_disks::DEVICE_MEDIA_UNKNOWN):
63       return DEVICE_TYPE_UNKNOWN;
64     case(cros_disks::DEVICE_MEDIA_USB):
65       return DEVICE_TYPE_USB;
66     case(cros_disks::DEVICE_MEDIA_SD):
67       return DEVICE_TYPE_SD;
68     case(cros_disks::DEVICE_MEDIA_OPTICAL_DISC):
69       return DEVICE_TYPE_OPTICAL_DISC;
70     case(cros_disks::DEVICE_MEDIA_MOBILE):
71       return DEVICE_TYPE_MOBILE;
72     case(cros_disks::DEVICE_MEDIA_DVD):
73       return DEVICE_TYPE_DVD;
74     default:
75       return DEVICE_TYPE_UNKNOWN;
76   }
77 }
78
79 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