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