• 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 
ReadMountEntryFromDbus(dbus::MessageReader * reader,MountEntry * entry)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:
CrosDisksClientImpl()98   CrosDisksClientImpl() : proxy_(NULL), weak_ptr_factory_(this) {}
99 
100   // 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)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.
Unmount(const std::string & device_path,UnmountOptions options,const base::Closure & callback,const base::Closure & error_callback)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.
EnumerateAutoMountableDevices(const EnumerateAutoMountableDevicesCallback & callback,const base::Closure & error_callback)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.
EnumerateMountEntries(const EnumerateMountEntriesCallback & callback,const base::Closure & error_callback)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.
Format(const std::string & device_path,const std::string & filesystem,const base::Closure & callback,const base::Closure & error_callback)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.
GetDeviceProperties(const std::string & device_path,const GetDevicePropertiesCallback & callback,const base::Closure & error_callback)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.
SetMountEventHandler(const MountEventHandler & mount_event_handler)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.
SetMountCompletedHandler(const MountCompletedHandler & mount_completed_handler)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.
SetFormatCompletedHandler(const FormatCompletedHandler & format_completed_handler)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:
Init(dbus::Bus * bus)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|.
OnMount(const base::Closure & callback,const base::Closure & error_callback,dbus::Response * response)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|.
OnUnmount(const base::Closure & callback,const base::Closure & error_callback,dbus::Response * response)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|.
OnEnumerateAutoMountableDevices(const EnumerateAutoMountableDevicesCallback & callback,const base::Closure & error_callback,dbus::Response * response)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|.
OnEnumerateMountEntries(const EnumerateMountEntriesCallback & callback,const base::Closure & error_callback,dbus::Response * response)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|.
OnFormat(const base::Closure & callback,const base::Closure & error_callback,dbus::Response * response)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|.
OnGetDeviceProperties(const std::string & device_path,const GetDevicePropertiesCallback & callback,const base::Closure & error_callback,dbus::Response * response)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|.
OnMountEvent(MountEventType event_type,MountEventHandler handler,dbus::Signal * signal)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|.
OnMountCompleted(MountCompletedHandler handler,dbus::Signal * signal)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|.
OnFormatCompleted(FormatCompletedHandler handler,dbus::Signal * signal)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.
OnSignalConnected(const std::string & interface,const std::string & signal,bool succeeded)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:
CrosDisksClientStubImpl()460   CrosDisksClientStubImpl()
461       : weak_ptr_factory_(this) {}
462 
~CrosDisksClientStubImpl()463   virtual ~CrosDisksClientStubImpl() {}
464 
465   // CrosDisksClient overrides:
Init(dbus::Bus * bus)466   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)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 
Unmount(const std::string & device_path,UnmountOptions options,const base::Closure & callback,const base::Closure & error_callback)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 
EnumerateAutoMountableDevices(const EnumerateAutoMountableDevicesCallback & callback,const base::Closure & error_callback)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 
EnumerateMountEntries(const EnumerateMountEntriesCallback & callback,const base::Closure & error_callback)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 
Format(const std::string & device_path,const std::string & filesystem,const base::Closure & callback,const base::Closure & error_callback)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 
GetDeviceProperties(const std::string & device_path,const GetDevicePropertiesCallback & callback,const base::Closure & error_callback)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 
SetMountEventHandler(const MountEventHandler & mount_event_handler)550   virtual void SetMountEventHandler(
551       const MountEventHandler& mount_event_handler) OVERRIDE {
552     mount_event_handler_ = mount_event_handler;
553   }
554 
SetMountCompletedHandler(const MountCompletedHandler & mount_completed_handler)555   virtual void SetMountCompletedHandler(
556       const MountCompletedHandler& mount_completed_handler) OVERRIDE {
557     mount_completed_handler_ = mount_completed_handler;
558   }
559 
SetFormatCompletedHandler(const FormatCompletedHandler & format_completed_handler)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().
PerformFakeMount(const std::string & source_path,const base::FilePath & mounted_path)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.
ContinueMount(const std::string & source_path,MountType type,const base::Closure & callback,const base::FilePath & mounted_path,MountError mount_error)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.
FinishMount(MountError error,const std::string & source_path,MountType type,const std::string & mounted_path,const base::Closure & callback)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 
DiskInfo(const std::string & device_path,dbus::Response * response)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       device_type_(DEVICE_TYPE_UNKNOWN),
650       total_size_in_bytes_(0),
651       is_read_only_(false),
652       is_hidden_(true) {
653   InitializeFromResponse(response);
654 }
655 
~DiskInfo()656 DiskInfo::~DiskInfo() {
657 }
658 
659 // Initializes |this| from |response| given by the cros-disks service.
660 // Below is an example of |response|'s raw message (long string is ellipsized).
661 //
662 //
663 // message_type: MESSAGE_METHOD_RETURN
664 // destination: :1.8
665 // sender: :1.16
666 // signature: a{sv}
667 // serial: 96
668 // reply_serial: 267
669 //
670 // array [
671 //   dict entry {
672 //     string "DeviceFile"
673 //     variant       string "/dev/sdb"
674 //   }
675 //   dict entry {
676 //     string "DeviceIsDrive"
677 //     variant       bool true
678 //   }
679 //   dict entry {
680 //     string "DeviceIsMediaAvailable"
681 //     variant       bool true
682 //   }
683 //   dict entry {
684 //     string "DeviceIsMounted"
685 //     variant       bool false
686 //   }
687 //   dict entry {
688 //     string "DeviceIsOnBootDevice"
689 //     variant       bool false
690 //   }
691 //   dict entry {
692 //     string "DeviceIsReadOnly"
693 //     variant       bool false
694 //   }
695 //   dict entry {
696 //     string "DeviceIsVirtual"
697 //     variant       bool false
698 //   }
699 //   dict entry {
700 //     string "DeviceMediaType"
701 //     variant       uint32 1
702 //   }
703 //   dict entry {
704 //     string "DeviceMountPaths"
705 //     variant       array [
706 //       ]
707 //   }
708 //   dict entry {
709 //     string "DevicePresentationHide"
710 //     variant       bool true
711 //   }
712 //   dict entry {
713 //     string "DeviceSize"
714 //     variant       uint64 7998537728
715 //   }
716 //   dict entry {
717 //     string "DriveIsRotational"
718 //     variant       bool false
719 //   }
720 //   dict entry {
721 //     string "VendorId"
722 //     variant       string "18d1"
723 //   }
724 //   dict entry {
725 //     string "VendorName"
726 //     variant       string "Google Inc."
727 //   }
728 //   dict entry {
729 //     string "ProductId"
730 //     variant       string "4e11"
731 //   }
732 //   dict entry {
733 //     string "ProductName"
734 //     variant       string "Nexus One"
735 //   }
736 //   dict entry {
737 //     string "DriveModel"
738 //     variant       string "TransMemory"
739 //   }
740 //   dict entry {
741 //     string "IdLabel"
742 //     variant       string ""
743 //   }
744 //   dict entry {
745 //     string "IdUuid"
746 //     variant       string ""
747 //   }
748 //   dict entry {
749 //     string "NativePath"
750 //     variant       string "/sys/devices/pci0000:00/0000:00:1d.7/usb1/1-4/...
751 //   }
752 // ]
InitializeFromResponse(dbus::Response * response)753 void DiskInfo::InitializeFromResponse(dbus::Response* response) {
754   dbus::MessageReader reader(response);
755   scoped_ptr<base::Value> value(dbus::PopDataAsValue(&reader));
756   base::DictionaryValue* properties = NULL;
757   if (!value || !value->GetAsDictionary(&properties))
758     return;
759 
760   properties->GetBooleanWithoutPathExpansion(
761       cros_disks::kDeviceIsDrive, &is_drive_);
762   properties->GetBooleanWithoutPathExpansion(
763       cros_disks::kDeviceIsReadOnly, &is_read_only_);
764   properties->GetBooleanWithoutPathExpansion(
765       cros_disks::kDevicePresentationHide, &is_hidden_);
766   properties->GetBooleanWithoutPathExpansion(
767       cros_disks::kDeviceIsMediaAvailable, &has_media_);
768   properties->GetBooleanWithoutPathExpansion(
769       cros_disks::kDeviceIsOnBootDevice, &on_boot_device_);
770   properties->GetStringWithoutPathExpansion(
771       cros_disks::kNativePath, &system_path_);
772   properties->GetStringWithoutPathExpansion(
773       cros_disks::kDeviceFile, &file_path_);
774   properties->GetStringWithoutPathExpansion(cros_disks::kVendorId, &vendor_id_);
775   properties->GetStringWithoutPathExpansion(
776       cros_disks::kVendorName, &vendor_name_);
777   properties->GetStringWithoutPathExpansion(
778       cros_disks::kProductId, &product_id_);
779   properties->GetStringWithoutPathExpansion(
780       cros_disks::kProductName, &product_name_);
781   properties->GetStringWithoutPathExpansion(
782       cros_disks::kDriveModel, &drive_model_);
783   properties->GetStringWithoutPathExpansion(cros_disks::kIdLabel, &label_);
784   properties->GetStringWithoutPathExpansion(cros_disks::kIdUuid, &uuid_);
785 
786   // dbus::PopDataAsValue() pops uint64 as double.
787   // The top 11 bits of uint64 are dropped by the use of double. But, this works
788   // unless the size exceeds 8 PB.
789   double device_size_double = 0;
790   if (properties->GetDoubleWithoutPathExpansion(cros_disks::kDeviceSize,
791                                                 &device_size_double))
792     total_size_in_bytes_ = device_size_double;
793 
794   // dbus::PopDataAsValue() pops uint32 as double.
795   double media_type_double = 0;
796   if (properties->GetDoubleWithoutPathExpansion(cros_disks::kDeviceMediaType,
797                                                 &media_type_double))
798     device_type_ = DeviceMediaTypeToDeviceType(media_type_double);
799 
800   base::ListValue* mount_paths = NULL;
801   if (properties->GetListWithoutPathExpansion(cros_disks::kDeviceMountPaths,
802                                               &mount_paths))
803     mount_paths->GetString(0, &mount_path_);
804 }
805 
806 ////////////////////////////////////////////////////////////////////////////////
807 // CrosDisksClient
808 
CrosDisksClient()809 CrosDisksClient::CrosDisksClient() {}
810 
~CrosDisksClient()811 CrosDisksClient::~CrosDisksClient() {}
812 
813 // static
Create(DBusClientImplementationType type)814 CrosDisksClient* CrosDisksClient::Create(DBusClientImplementationType type) {
815   if (type == REAL_DBUS_CLIENT_IMPLEMENTATION)
816     return new CrosDisksClientImpl();
817   DCHECK_EQ(STUB_DBUS_CLIENT_IMPLEMENTATION, type);
818   return new CrosDisksClientStubImpl();
819 }
820 
821 // static
GetArchiveMountPoint()822 base::FilePath CrosDisksClient::GetArchiveMountPoint() {
823   return base::FilePath(base::SysInfo::IsRunningOnChromeOS() ?
824                         FILE_PATH_LITERAL("/media/archive") :
825                         FILE_PATH_LITERAL("/tmp/chromeos/media/archive"));
826 }
827 
828 // static
GetRemovableDiskMountPoint()829 base::FilePath CrosDisksClient::GetRemovableDiskMountPoint() {
830   return base::FilePath(base::SysInfo::IsRunningOnChromeOS() ?
831                         FILE_PATH_LITERAL("/media/removable") :
832                         FILE_PATH_LITERAL("/tmp/chromeos/media/removable"));
833 }
834 
835 }  // namespace chromeos
836