Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(357)

Side by Side Diff: chrome/browser/chromeos/dbus/cros_disks_client.cc

Issue 8386031: Move chromeos_mount.cc from libcros to Chrome tree (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Fix for review comments Created 9 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2011 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 "chrome/browser/chromeos/dbus/cros_disks_client.h"
6
7 #include <set>
8 #include <vector>
9
10 #include <sys/statvfs.h>
11
12 #include "base/bind.h"
13 #include "base/memory/scoped_vector.h"
14 #include "base/string_util.h"
15 #include "chrome/browser/chromeos/system/runtime_environment.h"
16 #include "content/public/browser/browser_thread.h"
17 #include "dbus/bus.h"
18 #include "dbus/message.h"
19 #include "dbus/object_proxy.h"
20 #include "third_party/cros_system_api/dbus/service_constants.h"
21
22 using content::BrowserThread;
23
24 namespace chromeos {
25
26 namespace {
27
28 const char* kDeviceNotFound = "Device could not be found";
29
30 const char* kDefaultMountOptions[] = {
31 "rw",
32 "nodev",
33 "noexec",
34 "nosuid",
35 "sync"
36 };
37 const char* kDefaultUnmountOptions[] = {
38 "force"
39 };
40
41 enum MountEventType {
42 DISK_ADDED,
43 DISK_REMOVED,
44 DISK_CHANGED,
45 DEVICE_ADDED,
46 DEVICE_REMOVED,
47 DEVICE_SCANNED,
48 FORMATTING_FINISHED,
49 };
50
51 class DiskInfo {
52 public:
53 DiskInfo(const std::string& device_path, dbus::Response* response)
54 : device_path_(device_path),
55 is_drive_(false),
56 has_media_(false),
57 on_boot_device_(false),
58 device_type_(UNDEFINED),
59 total_size_(0),
60 is_read_only_(false),
61 is_hidden_(true) {
62 InitializeFromResponse(response);
63 }
64
65 // Device path. (e.g. /sys/devices/pci0000:00/.../8:0:0:0/block/sdb/sdb1)
66 std::string device_path() const { return device_path_; }
67
68 // Disk mount path. (e.g. /media/removable/VOLUME)
69 std::string mount_path() const { return mount_path_; }
70
71 // Disk system path given by udev.
72 // (e.g. /sys/devices/pci0000:00/.../8:0:0:0/block/sdb/sdb1)
73 std::string system_path() const { return system_path_; }
74
75 // Is disk into a drive (i.e. /dev/sdb vs, /dev/sdb1).
76 bool is_drive() const { return is_drive_; }
77
78 // Does the disk have media content.
79 bool has_media() const { return has_media_; }
80
81 // Is the disk on deveice we booted the machien from.
82 bool on_boot_device() const { return on_boot_device_; }
83
84 // Disk file path (e.g /dev/sdb).
85 std::string file_path() const { return file_path_; }
86
87 // Disk label.
88 std::string label() const { return label_; }
89
90 // Disk model
91 std::string drive_label() const { return drive_model_; }
92
93 // Partition table path of the device, if device is partition.
94 std::string partition_slave() const { return partition_slave_; }
95
96 // Device type. Not working well, yet.
97 DeviceType device_type() const { return device_type_; }
98
99 // Total size of the disk.
100 uint64 size() const { return total_size_; }
101
102 // Is the device read-only.
103 bool is_read_only() const { return is_read_only_; }
104
105 bool is_hidden() const { return is_hidden_; }
106
107 private:
108 // Returns the device type from the given arguments.
109 DeviceType GetDeviceType(bool is_optical, bool is_rotational) {
110 if (is_optical)
111 return OPTICAL;
112 if (is_rotational)
113 return HDD;
114 return FLASH;
115 }
116
117 // Pops a bool value when |reader| is not NULL.
118 // It returns true when a value is popped, false otherwise.
119 bool MaybePopBool(dbus::MessageReader* reader, bool* value) {
120 if (!reader)
121 return false;
122 return reader->PopBool(value);
123 }
124
125 // Pops a string value when |reader| is not NULL.
126 // It returns true when a value is popped, false otherwise.
127 bool MaybePopString(dbus::MessageReader* reader, std::string* value) {
128 if (!reader)
129 return false;
130 return reader->PopString(value);
131 }
132
133 // Pops a uint64 value when |reader| is not NULL.
134 // It returns true when a value is popped, false otherwise.
135 bool MaybePopUint64(dbus::MessageReader* reader, uint64* value) {
136 if (!reader)
137 return false;
138 return reader->PopUint64(value);
139 }
140
141 // Pops an array of strings when |reader| is not NULL.
142 // It returns true when an array is popped, false otherwise.
143 bool MaybePopArrayOfStrings(dbus::MessageReader* reader,
144 std::vector<std::string>* value) {
145 if (!reader)
146 return false;
147 return reader->PopArrayOfStrings(value);
148 }
149
150 // Initialize |this| from |response| given by the cros-disks service.
151 void InitializeFromResponse(dbus::Response* response) {
152 dbus::MessageReader response_reader(response);
153 dbus::MessageReader array_reader(response);
154 if (!response_reader.PopArray(&array_reader)) {
155 LOG(ERROR) << "Invalid response: " << response->ToString();
156 return;
157 }
158 // TODO(satorux): Rework this code using Protocol Buffers. crosbug.com/22626
159 ScopedVector<dbus::MessageReader> value_readers_owner;
160 std::map<std::string, dbus::MessageReader*> properties;
161 while (array_reader.HasMoreData()) {
162 // |value_readers_owner| is responsible to delete |value_reader|
163 dbus::MessageReader* value_reader = new dbus::MessageReader(response);
164 value_readers_owner.push_back(value_reader);
165 dbus::MessageReader dict_entry_reader(response);
166 std::string key;
167 if (!array_reader.PopDictEntry(&dict_entry_reader) ||
168 !dict_entry_reader.PopString(&key) ||
169 !dict_entry_reader.PopVariant(value_reader)) {
170 LOG(ERROR) << "Invalid response: " << response->ToString();
171 return;
172 }
173 properties[key] = value_reader;
174 }
175 MaybePopBool(properties[cros_disks::kDeviceIsDrive], &is_drive_);
176 MaybePopBool(properties[cros_disks::kDeviceIsReadOnly], &is_read_only_);
177 MaybePopBool(properties[cros_disks::kDevicePresentationHide], &is_hidden_);
178 MaybePopBool(properties[cros_disks::kDeviceIsMediaAvailable], &has_media_);
179 MaybePopBool(properties[cros_disks::kDeviceIsOnBootDevice],
180 &on_boot_device_);
181 MaybePopString(properties[cros_disks::kNativePath], &system_path_);
182 MaybePopString(properties[cros_disks::kDeviceFile], &file_path_);
183 MaybePopString(properties[cros_disks::kDriveModel], &drive_model_);
184 MaybePopString(properties[cros_disks::kIdLabel], &label_);
185 MaybePopUint64(properties[cros_disks::kDeviceSize], &total_size_);
186
187 std::vector<std::string> mount_paths;
188 if (MaybePopArrayOfStrings(properties[cros_disks::kDeviceMountPaths],
189 &mount_paths) && !mount_paths.empty())
190 mount_path_ = mount_paths[0];
191
192 bool is_rotational, is_optical;
193 if (MaybePopBool(properties[cros_disks::kDriveIsRotational],
194 &is_rotational) &&
195 MaybePopBool(properties[cros_disks::kDeviceIsOpticalDisc],
196 &is_optical))
197 device_type_ = GetDeviceType(is_optical, is_rotational);
198 }
199
200 std::string device_path_;
201 std::string mount_path_;
202 std::string system_path_;
203 bool is_drive_;
204 bool has_media_;
205 bool on_boot_device_;
206
207 std::string file_path_;
208 std::string label_;
209 std::string drive_model_;
210 std::string partition_slave_;
211 DeviceType device_type_;
212 uint64 total_size_;
213 bool is_read_only_;
214 bool is_hidden_;
215 };
216
217 // A class to make the actual DBus calls for cros-disks service.
218 // This class only makes calls, result/error handling should be done
219 // by callbacks.
220 class CrosDisksDBusProxy {
221 public:
222 // A callback to be called when DBus method call fails.
223 typedef base::Callback<void()> ErrorCallback;
224
225 // A callback to handle the result of Mount.
226 typedef base::Callback<void()> MountCallback;
227
228 // A callback to handle the result of Unmount.
229 // The argument is the device path.
230 typedef base::Callback<void(const std::string&)> UnmountCallback;
231
232 // A callback to handle the result of EnumerateAutoMountableDevices.
233 // The argument is the enumerated device paths.
234 typedef base::Callback<void(const std::vector<std::string>&)
235 > EnumerateAutoMountableDevicesCallback;
236
237 // A callback to handle the result of FormatDevice.
238 // The first argument is the device path.
239 // The second argument is true when formatting succeeded, false otherwise.
240 typedef base::Callback<void(const std::string&, bool)> FormatDeviceCallback;
241
242 // A callback to handle the result of GetDeviceProperties.
243 // The argument is the information about the specified device.
244 typedef base::Callback<void(const DiskInfo&)> GetDevicePropertiesCallback;
245
246 // A callback to handle MountCompleted signal.
247 // The first argument is the error code.
248 // The second argument is the source path.
249 // The third argument is the mount type.
250 // The fourth argument is the mount path.
251 typedef base::Callback<void(MountError, const std::string&, MountType,
252 const std::string&)> MountCompletedHandler;
253
254 // A callback to handle mount events.
255 // The first argument is the event type.
256 // The second argument is the device path.
257 typedef base::Callback<void(MountEventType, const std::string&)
258 > MountEventHandler;
259
260 explicit CrosDisksDBusProxy(dbus::Bus* bus)
261 : proxy_(bus->GetObjectProxy(cros_disks::kCrosDisksServiceName,
262 cros_disks::kCrosDisksServicePath)),
263 weak_ptr_factory_(this) {
264 }
265
266 // Calls Mount method. |callback| is called after the method call succeeds,
267 // otherwise, |error_callback| is called.
268 void Mount(const std::string& source_path,
269 MountType type,
270 const MountPathOptions& options,
271 MountCallback callback,
272 ErrorCallback error_callback) {
273 dbus::MethodCall method_call(cros_disks::kCrosDisksInterface,
274 cros_disks::kMount);
275 dbus::MessageWriter writer(&method_call);
276 writer.AppendString(source_path);
277 writer.AppendString(""); // auto detect filesystem.
278 std::vector<std::string> mount_options(kDefaultMountOptions,
279 kDefaultMountOptions +
280 arraysize(kDefaultMountOptions));
281 writer.AppendArrayOfStrings(mount_options);
282 proxy_->CallMethod(&method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
283 base::Bind(&CrosDisksDBusProxy::OnMount,
284 weak_ptr_factory_.GetWeakPtr(),
285 callback,
286 error_callback));
287 }
288
289 // Calls Unmount method. |callback| is called after the method call succeeds,
290 // otherwise, |error_callback| is called.
291 void Unmount(const std::string& device_path,
292 UnmountCallback callback,
293 ErrorCallback error_callback) {
294 dbus::MethodCall method_call(cros_disks::kCrosDisksInterface,
295 cros_disks::kUnmount);
296 dbus::MessageWriter writer(&method_call);
297 writer.AppendString(device_path);
298 std::vector<std::string> unmount_options(kDefaultUnmountOptions,
299 kDefaultUnmountOptions +
300 arraysize(kDefaultUnmountOptions));
301 writer.AppendArrayOfStrings(unmount_options);
302 proxy_->CallMethod(&method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
303 base::Bind(&CrosDisksDBusProxy::OnUnmount,
304 weak_ptr_factory_.GetWeakPtr(),
305 device_path,
306 callback,
307 error_callback));
308 }
309
310 // Calls EnumerateAutoMountableDevices method. |callback| is called after the
311 // method call succeeds, otherwise, |error_callback| is called.
312 void EnumerateAutoMountableDevices(
313 EnumerateAutoMountableDevicesCallback callback,
314 ErrorCallback error_callback) {
315 dbus::MethodCall method_call(cros_disks::kCrosDisksInterface,
316 cros_disks::kEnumerateAutoMountableDevices);
317 proxy_->CallMethod(
318 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
319 base::Bind(&CrosDisksDBusProxy::OnEnumerateAutoMountableDevices,
320 weak_ptr_factory_.GetWeakPtr(),
321 callback,
322 error_callback));
323 }
324
325 // Calls FormatDevice method. |callback| is called after the method call
326 // succeeds, otherwise, |error_callback| is called.
327 void FormatDevice(const std::string& device_path,
328 const std::string& filesystem,
329 FormatDeviceCallback callback,
330 ErrorCallback error_callback) {
331 dbus::MethodCall method_call(cros_disks::kCrosDisksInterface,
332 cros_disks::kFormatDevice);
333 dbus::MessageWriter writer(&method_call);
334 writer.AppendString(device_path);
335 writer.AppendString(filesystem);
336 proxy_->CallMethod(&method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
337 base::Bind(&CrosDisksDBusProxy::OnFormatDevice,
338 weak_ptr_factory_.GetWeakPtr(),
339 device_path,
340 callback,
341 error_callback));
342 }
343
344 // Calls GetDeviceProperties method. |callback| is called after the method
345 // call succeeds, otherwise, |error_callback| is called.
346 void GetDeviceProperties(const std::string& device_path,
347 GetDevicePropertiesCallback callback,
348 ErrorCallback error_callback) {
349 dbus::MethodCall method_call(cros_disks::kCrosDisksInterface,
350 cros_disks::kGetDeviceProperties);
351 dbus::MessageWriter writer(&method_call);
352 writer.AppendString(device_path);
353 proxy_->CallMethod(&method_call,
354 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
355 base::Bind(&CrosDisksDBusProxy::OnGetDeviceProperties,
356 weak_ptr_factory_.GetWeakPtr(),
357 device_path,
358 callback,
359 error_callback));
360 }
361
362 // Registers given callback for events.
363 // |mount_event_handler| is called when mount event signal is received.
364 // |mount_completed_handler| is called when MountCompleted signal is received.
365 void SetUpConnections(MountEventHandler mount_event_handler,
366 MountCompletedHandler mount_completed_handler) {
367 static const SignalEventTuple kSignalEventTuples[] = {
368 { "DeviceAdded", DEVICE_ADDED },
369 { "DeviceScanned", DEVICE_SCANNED },
370 { "DeviceRemoved", DEVICE_REMOVED },
371 { "DiskAdded", DISK_ADDED },
372 { "DiskChanged", DISK_CHANGED },
373 { "DiskRemoved", DISK_REMOVED },
374 { "FormattingFinished", FORMATTING_FINISHED },
375 };
376 const size_t kNumSignalEventTuples = arraysize(kSignalEventTuples);
377
378 for (size_t i = 0; i < kNumSignalEventTuples; ++i) {
379 proxy_->ConnectToSignal(
380 cros_disks::kCrosDisksInterface,
381 kSignalEventTuples[i].signal_name,
382 base::Bind(&CrosDisksDBusProxy::OnMountEvent,
383 weak_ptr_factory_.GetWeakPtr(),
384 kSignalEventTuples[i].event_type,
385 mount_event_handler),
386 base::Bind(&CrosDisksDBusProxy::OnSignalConnected,
387 weak_ptr_factory_.GetWeakPtr()));
388 }
389 proxy_->ConnectToSignal(
390 cros_disks::kCrosDisksInterface,
391 "MountCompleted",
392 base::Bind(&CrosDisksDBusProxy::OnMountCompleted,
393 weak_ptr_factory_.GetWeakPtr(),
394 mount_completed_handler ),
395 base::Bind(&CrosDisksDBusProxy::OnSignalConnected,
396 weak_ptr_factory_.GetWeakPtr()));
397 }
398
399 private:
400 struct SignalEventTuple {
401 const char *signal_name;
402 MountEventType event_type;
403 };
404
405 // Handles the result of Mount and calls |callback| or |error_callback|
406 void OnMount(MountCallback callback,
407 ErrorCallback error_callback,
408 dbus::Response* response) {
409 if (!response) {
410 error_callback.Run();
411 return;
412 }
413 callback.Run();
414 }
415
416 // Handles the result of Unount and calls |callback| or |error_callback|
417 void OnUnmount(const std::string& device_path,
418 UnmountCallback callback,
419 ErrorCallback error_callback,
420 dbus::Response* response) {
421 if (!response) {
422 error_callback.Run();
423 return;
424 }
425 callback.Run(device_path);
426 }
427
428 // Handles the result of EnumerateAutoMountableDevices and calls |callback| or
429 // |error_callback|
430 void OnEnumerateAutoMountableDevices(
431 EnumerateAutoMountableDevicesCallback callback,
432 ErrorCallback error_callback,
433 dbus::Response* response) {
434 if (!response) {
435 error_callback.Run();
436 return;
437 }
438 dbus::MessageReader reader(response);
439 std::vector<std::string> device_paths;
440 if (!reader.PopArrayOfStrings(&device_paths)) {
441 LOG(ERROR) << "Invalid response: " << response->ToString();
442 error_callback.Run();
443 return;
444 }
445 callback.Run(device_paths);
446 }
447
448 // Handles the result of FormatDevice and calls |callback| or |error_callback|
449 void OnFormatDevice(const std::string& device_path,
450 FormatDeviceCallback callback,
451 ErrorCallback error_callback,
452 dbus::Response* response) {
453 if (!response) {
454 error_callback.Run();
455 return;
456 }
457 dbus::MessageReader reader(response);
458 bool success = false;
459 if (!reader.PopBool(&success)) {
460 LOG(ERROR) << "Invalid response: " << response->ToString();
461 error_callback.Run();
462 return;
463 }
464 callback.Run(device_path, success);
465 }
466
467 // Handles the result of GetDeviceProperties and calls |callback| or
468 // |error_callback|
469 void OnGetDeviceProperties(const std::string& device_path,
470 GetDevicePropertiesCallback callback,
471 ErrorCallback error_callback,
472 dbus::Response* response) {
473 if (!response) {
474 error_callback.Run();
475 return;
476 }
477 DiskInfo disk(device_path, response);
478 callback.Run(disk);
479 }
480
481 // Handles mount event signals and calls |handler|
482 void OnMountEvent(MountEventType event_type,
483 MountEventHandler handler,
484 dbus::Signal* signal) {
485 dbus::MessageReader reader(signal);
486 std::string device;
487 if (!reader.PopString(&device)) {
488 LOG(ERROR) << "Invalid signal: " << signal->ToString();
489 return;
490 }
491 handler.Run(event_type, device);
492 }
493
494 // Handles MountCompleted signal and calls |handler|
495 void OnMountCompleted(MountCompletedHandler handler, dbus::Signal* signal) {
496 dbus::MessageReader reader(signal);
497 unsigned int error_code = 0;
498 std::string source_path;
499 unsigned int mount_type = 0;
500 std::string mount_path;
501 if (!reader.PopUint32(&error_code) ||
502 !reader.PopString(&source_path) ||
503 !reader.PopUint32(&mount_type) ||
504 !reader.PopString(&mount_path)) {
505 LOG(ERROR) << "Invalid signal: " << signal->ToString();
506 return;
507 }
508 handler.Run(static_cast<MountError>(error_code), source_path,
509 static_cast<MountType>(mount_type), mount_path);
510 }
511
512 // Handles the result of signal connection setup.
513 void OnSignalConnected(const std::string& interface,
514 const std::string& signal,
515 bool successed) {
516 LOG_IF(ERROR, !successed) << "Connect to " << interface << " " <<
517 signal << " failed.";
518 }
519
520 dbus::ObjectProxy* proxy_;
521 base::WeakPtrFactory<CrosDisksDBusProxy> weak_ptr_factory_;
522 };
523
524 // The cros-disks implementation.
525 class CrosDisksClientImpl : public CrosDisksClient {
526 public:
527 explicit CrosDisksClientImpl(dbus::Bus* bus)
528 : dbus_proxy_(new CrosDisksDBusProxy(bus)),
529 weak_ptr_factory_(this) {
530 dbus_proxy_->SetUpConnections(
531 base::Bind(&CrosDisksClientImpl::OnMountEvent,
532 weak_ptr_factory_.GetWeakPtr()),
533 base::Bind(&CrosDisksClientImpl::OnMountCompleted,
534 weak_ptr_factory_.GetWeakPtr()));
535 }
536
537 ~CrosDisksClientImpl() {
538 }
539
540 virtual void AddObserver(Observer* observer) OVERRIDE {
541 observers_.AddObserver(observer);
542 }
543
544 virtual void RemoveObserver(Observer* observer) OVERRIDE {
545 observers_.RemoveObserver(observer);
546 }
547
548 virtual void MountPath(const std::string& source_path,
549 MountType type,
550 const MountPathOptions& options) OVERRIDE {
551 // Hidden and non-existent devices should not be mounted.
552 if (type == MOUNT_TYPE_DEVICE) {
553 DiskMap::const_iterator it = disks_.find(source_path);
554 if (it == disks_.end() || it->second->is_hidden()) {
555 OnMountCompleted(MOUNT_ERROR_INTERNAL, source_path, type, "");
556 return;
557 }
558 }
559 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
560 dbus_proxy_->Mount(source_path, type, options,
561 // When succeeds, OnMountCompleted will be called by
562 // "MountCompleted" signal instead.
563 base::Bind(&DoNothing),
564 base::Bind(&CrosDisksClientImpl::OnMountCompleted,
565 weak_ptr_factory_.GetWeakPtr(),
566 MOUNT_ERROR_INTERNAL,
567 source_path,
568 type,
569 ""));
570 }
571
572 virtual void UnmountPath(const std::string& mount_path) OVERRIDE {
573 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
574 dbus_proxy_->Unmount(mount_path,
575 base::Bind(&CrosDisksClientImpl::OnUnmountPath,
576 weak_ptr_factory_.GetWeakPtr()),
577 base::Bind(&DoNothing));
578 }
579
580 virtual void GetSizeStatsOnFileThread(const std::string& mount_path,
581 size_t* total_size_kb,
582 size_t* remaining_size_kb) OVERRIDE {
583 CHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
584
585 uint64_t total_size_uint64 = 0;
586 uint64_t remaining_size_uint64 = 0;
587
588 struct statvfs stat = {}; // Zero-clear
589 if (statvfs(mount_path.c_str(), &stat) == 0) {
590 total_size_uint64 =
591 static_cast<uint64_t>(stat.f_blocks) * stat.f_frsize;
592 remaining_size_uint64 =
593 static_cast<uint64_t>(stat.f_bfree) * stat.f_frsize;
594 }
595 *total_size_kb = static_cast<size_t>(total_size_uint64 / 1024);
596 *remaining_size_kb = static_cast<size_t>(remaining_size_uint64 / 1024);
597 }
598
599 virtual void FormatUnmountedDevice(const std::string& file_path) OVERRIDE {
600 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
601 for (CrosDisksClient::DiskMap::iterator it = disks_.begin();
602 it != disks_.end(); ++it) {
603 if (it->second->file_path() == file_path &&
604 !it->second->mount_path().empty()) {
605 LOG(ERROR) << "Device is still mounted: " << file_path;
606 OnFormatDevice(file_path, false);
607 return;
608 }
609 }
610 const char kFormatVFAT[] = "vfat";
611 dbus_proxy_->FormatDevice(file_path, kFormatVFAT,
612 base::Bind(&CrosDisksClientImpl::OnFormatDevice,
613 weak_ptr_factory_.GetWeakPtr()),
614 base::Bind(&CrosDisksClientImpl::OnFormatDevice,
615 weak_ptr_factory_.GetWeakPtr(),
616 file_path,
617 false));
618 }
619
620 virtual void FormatMountedDevice(const std::string& mount_path) OVERRIDE {
621 Disk* disk = NULL;
622 for (CrosDisksClient::DiskMap::iterator it = disks_.begin();
623 it != disks_.end(); ++it) {
624 if (it->second->mount_path() == mount_path) {
625 disk = it->second;
626 break;
627 }
628 }
629 if (!disk) {
630 LOG(ERROR) << "Device with this mount path not found: " << mount_path;
631 OnFormatDevice(mount_path, false);
632 return;
633 }
634 if (formatting_pending_.find(disk->device_path()) !=
635 formatting_pending_.end()) {
636 LOG(ERROR) << "Formatting is already pending: " << mount_path;
637 OnFormatDevice(mount_path, false);
638 return;
639 }
640 // Formatting process continues, after unmounting.
641 formatting_pending_[disk->device_path()] = disk->file_path();
642 UnmountPath(disk->mount_path());
643 }
644
645 virtual void UnmountDeviceRecursive(
646 const std::string& device_path,
647 UnmountDeviceRecursiveCallbackType callback,
648 void* user_data) OVERRIDE {
649 bool success = true;
650 std::string error_message;
651 std::vector<std::string> devices_to_unmount;
652
653 // Get list of all devices to unmount.
654 int device_path_len = device_path.length();
655 for (DiskMap::iterator it = disks_.begin(); it != disks_.end(); ++it) {
656 if (!it->second->mount_path().empty() &&
657 strncmp(device_path.c_str(), it->second->device_path().c_str(),
658 device_path_len) == 0) {
659 devices_to_unmount.push_back(it->second->mount_path());
660 }
661 }
662 // We should detect at least original device.
663 if (devices_to_unmount.empty()) {
664 if (disks_.find(device_path) == disks_.end()) {
665 success = false;
666 error_message = kDeviceNotFound;
667 } else {
668 // Nothing to unmount.
669 callback(user_data, true);
670 return;
671 }
672 }
673 if (success) {
674 // We will send the same callback data object to all Unmount calls and use
675 // it to syncronize callbacks.
676 UnmountDeviceRecursiveCallbackData* cb_data =
677 new UnmountDeviceRecursiveCallbackData(user_data, callback,
678 devices_to_unmount.size());
679 for (std::vector<std::string>::iterator it = devices_to_unmount.begin();
680 it != devices_to_unmount.end();
681 ++it) {
682 dbus_proxy_->Unmount(
683 *it,
684 base::Bind(&CrosDisksClientImpl::OnUnmountDeviceRecursive,
685 weak_ptr_factory_.GetWeakPtr(), cb_data, true),
686 base::Bind(&CrosDisksClientImpl::OnUnmountDeviceRecursive,
687 weak_ptr_factory_.GetWeakPtr(), cb_data, false, *it));
688 }
689 } else {
690 LOG(WARNING) << "Unmount recursive request failed for device "
691 << device_path << ", with error: " << error_message;
692 callback(user_data, false);
693 }
694 }
695
696 virtual void RequestMountInfoRefresh() OVERRIDE {
697 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
698 dbus_proxy_->EnumerateAutoMountableDevices(
699 base::Bind(&CrosDisksClientImpl::OnRequestMountInfo,
700 weak_ptr_factory_.GetWeakPtr()),
701 base::Bind(&DoNothing));
702 }
703
704 const DiskMap& disks() const OVERRIDE { return disks_; }
705 const MountPointMap& mount_points() const OVERRIDE { return mount_points_; }
706
707 private:
708 struct UnmountDeviceRecursiveCallbackData {
709 void* user_data;
710 UnmountDeviceRecursiveCallbackType callback;
711 size_t pending_callbacks_count;
712
713 UnmountDeviceRecursiveCallbackData(void* ud,
714 UnmountDeviceRecursiveCallbackType cb,
715 int count)
716 : user_data(ud),
717 callback(cb),
718 pending_callbacks_count(count) {
719 }
720 };
721
722 // Callback for UnmountDeviceRecursive.
723 void OnUnmountDeviceRecursive(UnmountDeviceRecursiveCallbackData* cb_data,
724 bool success,
725 const std::string& mount_path) {
726 if (success) {
727 // Do standard processing for Unmount event.
728 OnUnmountPath(mount_path);
729 LOG(INFO) << mount_path << " unmounted.";
730 }
731 // This is safe as long as all callbacks are called on the same thread as
732 // UnmountDeviceRecursive.
733 cb_data->pending_callbacks_count--;
734
735 if (cb_data->pending_callbacks_count == 0) {
736 cb_data->callback(cb_data->user_data, success);
737 delete cb_data;
738 }
739 }
740
741 // Callback to handle MountCompleted signal and Mount method call failure.
742 void OnMountCompleted(MountError error_code,
743 const std::string& source_path,
744 MountType type,
745 const std::string& mount_path) {
746 MountCondition mount_condition = MOUNT_CONDITION_NONE;
747 if (type == MOUNT_TYPE_DEVICE) {
748 if (error_code == MOUNT_ERROR_UNKNOWN_FILESYSTEM)
749 mount_condition = MOUNT_CONDITION_UNKNOWN_FILESYSTEM;
750 if (error_code == MOUNT_ERROR_UNSUPORTED_FILESYSTEM)
751 mount_condition = MOUNT_CONDITION_UNSUPPORTED_FILESYSTEM;
752 }
753 const MountPointInfo mount_info(source_path, mount_path, type,
754 mount_condition);
755
756 FireMountCompleted(MOUNTING, error_code, mount_info);
757
758 // If the device is corrupted but it's still possible to format it, it will
759 // be fake mounted.
760 if ((error_code == MOUNT_ERROR_NONE || mount_info.mount_condition) &&
761 mount_points_.find(mount_info.mount_path) == mount_points_.end()) {
762 mount_points_.insert(MountPointMap::value_type(mount_info.mount_path,
763 mount_info));
764 }
765 if ((error_code == MOUNT_ERROR_NONE || mount_info.mount_condition) &&
766 mount_info.mount_type == MOUNT_TYPE_DEVICE &&
767 !mount_info.source_path.empty() &&
768 !mount_info.mount_path.empty()) {
769 DiskMap::iterator iter = disks_.find(mount_info.source_path);
770 if (iter == disks_.end()) {
771 // disk might have been removed by now?
772 return;
773 }
774 Disk* disk = iter->second;
775 DCHECK(disk);
776 disk->set_mount_path(mount_info.mount_path);
777 FireDiskStatusUpdate(MOUNT_DISK_MOUNTED, disk);
778 }
779 }
780
781 // Callback for UnmountPath.
782 void OnUnmountPath(const std::string& mount_path) {
783 MountPointMap::iterator mount_points_it = mount_points_.find(mount_path);
784 if (mount_points_it == mount_points_.end())
785 return;
786 // TODO(tbarzic): Add separate, PathUnmounted event to Observer.
787 FireMountCompleted(UNMOUNTING,
788 MOUNT_ERROR_NONE,
789 MountPointInfo(mount_points_it->second.source_path,
790 mount_points_it->second.mount_path,
791 mount_points_it->second.mount_type,
792 mount_points_it->second.mount_condition));
793 std::string path(mount_points_it->second.source_path);
794 mount_points_.erase(mount_points_it);
795 DiskMap::iterator iter = disks_.find(path);
796 if (iter == disks_.end()) {
797 // disk might have been removed by now.
798 return;
799 }
800 Disk* disk = iter->second;
801 DCHECK(disk);
802 disk->clear_mount_path();
803 // Check if there is a formatting scheduled
804 PathMap::iterator it = formatting_pending_.find(disk->device_path());
805 if (it != formatting_pending_.end()) {
806 const std::string file_path = it->second;
807 formatting_pending_.erase(it);
808 FormatUnmountedDevice(file_path);
809 }
810 }
811
812 // Callback for FormatDevice.
813 void OnFormatDevice(const std::string& device_path, bool success) {
814 if (success) {
815 FireDeviceStatusUpdate(MOUNT_FORMATTING_STARTED, device_path);
816 } else {
817 FireDeviceStatusUpdate(MOUNT_FORMATTING_STARTED,
818 std::string("!") + device_path);
819 LOG(WARNING) << "Format request failed for device " << device_path;
820 }
821 }
822
823 // Callbcak for GetDeviceProperties.
824 void OnGetDeviceProperties(const DiskInfo& disk_info) {
825 // TODO(zelidrag): Find a better way to filter these out before we
826 // fetch the properties:
827 // Ignore disks coming from the device we booted the system from.
828 if (disk_info.on_boot_device())
829 return;
830
831 LOG(WARNING) << "Found disk " << disk_info.device_path();
832 // Delete previous disk info for this path:
833 bool is_new = true;
834 DiskMap::iterator iter = disks_.find(disk_info.device_path());
835 if (iter != disks_.end()) {
836 delete iter->second;
837 disks_.erase(iter);
838 is_new = false;
839 }
840 Disk* disk = new Disk(disk_info.device_path(),
841 disk_info.mount_path(),
842 disk_info.system_path(),
843 disk_info.file_path(),
844 disk_info.label(),
845 disk_info.drive_label(),
846 disk_info.partition_slave(),
847 FindSystemPathPrefix(disk_info.system_path()),
848 disk_info.device_type(),
849 disk_info.size(),
850 disk_info.is_drive(),
851 disk_info.is_read_only(),
852 disk_info.has_media(),
853 disk_info.on_boot_device(),
854 disk_info.is_hidden());
855 disks_.insert(std::pair<std::string, Disk*>(disk_info.device_path(),
856 disk));
857 FireDiskStatusUpdate(is_new ? MOUNT_DISK_ADDED : MOUNT_DISK_CHANGED, disk);
858 }
859
860 // Callbcak for RequestMountInfo.
861 void OnRequestMountInfo(const std::vector<std::string>& devices) {
862 std::set<std::string> current_device_set;
863 if (!devices.empty()) {
864 // Initiate properties fetch for all removable disks,
865 for (size_t i = 0; i < devices.size(); i++) {
866 current_device_set.insert(devices[i]);
867 // Initiate disk property retrieval for each relevant device path.
868 dbus_proxy_->GetDeviceProperties(
869 devices[i],
870 base::Bind(&CrosDisksClientImpl::OnGetDeviceProperties,
871 weak_ptr_factory_.GetWeakPtr()),
872 base::Bind(&DoNothing));
873 }
874 }
875 // Search and remove disks that are no longer present.
876 for (DiskMap::iterator iter = disks_.begin(); iter != disks_.end(); ) {
877 if (current_device_set.find(iter->first) == current_device_set.end()) {
878 Disk* disk = iter->second;
879 FireDiskStatusUpdate(MOUNT_DISK_REMOVED, disk);
880 delete iter->second;
881 disks_.erase(iter++);
882 } else {
883 ++iter;
884 }
885 }
886 }
887
888 // Callback to handle mount event signals.
889 void OnMountEvent(MountEventType evt, std::string device_path) {
890 CrosDisksClientEventType type = MOUNT_DEVICE_ADDED;
891 switch (evt) {
892 case DISK_ADDED: {
893 dbus_proxy_->GetDeviceProperties(
894 device_path,
895 base::Bind(&CrosDisksClientImpl::OnGetDeviceProperties,
896 weak_ptr_factory_.GetWeakPtr()),
897 base::Bind(&DoNothing));
898 return;
899 }
900 case DISK_REMOVED: {
901 // Search and remove disks that are no longer present.
902 CrosDisksClient::DiskMap::iterator iter = disks_.find(device_path);
903 if (iter != disks_.end()) {
904 Disk* disk = iter->second;
905 FireDiskStatusUpdate(MOUNT_DISK_REMOVED, disk);
906 delete iter->second;
907 disks_.erase(iter);
908 }
909 return;
910 }
911 case DEVICE_ADDED: {
912 type = MOUNT_DEVICE_ADDED;
913 system_path_prefixes_.insert(device_path);
914 break;
915 }
916 case DEVICE_REMOVED: {
917 type = MOUNT_DEVICE_REMOVED;
918 system_path_prefixes_.erase(device_path);
919 break;
920 }
921 case DEVICE_SCANNED: {
922 type = MOUNT_DEVICE_SCANNED;
923 break;
924 }
925 case FORMATTING_FINISHED: {
926 // FORMATTING_FINISHED actually returns file path instead of device
927 // path.
928 device_path = FilePathToDevicePath(device_path);
929 if (device_path.empty()) {
930 LOG(ERROR) << "Error while handling disks metadata. Cannot find "
931 << "device that is being formatted.";
932 return;
933 }
934 type = MOUNT_FORMATTING_FINISHED;
935 break;
936 }
937 default: {
938 return;
939 }
940 }
941 FireDeviceStatusUpdate(type, device_path);
942 }
943
944 // Notifies all observers about disk status update.
945 void FireDiskStatusUpdate(CrosDisksClientEventType evt, const Disk* disk) {
946 // Make sure we run on UI thread.
947 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
948 FOR_EACH_OBSERVER(Observer, observers_, DiskChanged(evt, disk));
949 }
950
951 // Notifies all observers about device status update.
952 void FireDeviceStatusUpdate(CrosDisksClientEventType evt,
953 const std::string& device_path) {
954 // Make sure we run on UI thread.
955 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
956 FOR_EACH_OBSERVER(Observer, observers_, DeviceChanged(evt, device_path));
957 }
958
959 // Notifies all observers about mount completion.
960 void FireMountCompleted(MountEvent event_type,
961 MountError error_code,
962 const MountPointInfo& mount_info) {
963 // Make sure we run on UI thread.
964 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
965 FOR_EACH_OBSERVER(Observer, observers_,
966 MountCompleted(event_type, error_code, mount_info));
967 }
968
969 // Converts file path to device path.
970 std::string FilePathToDevicePath(const std::string& file_path) {
971 int failed = (file_path[0] == '!') ? 1 : 0;
972 for (CrosDisksClient::DiskMap::iterator it = disks_.begin();
973 it != disks_.end(); ++it) {
974 if (it->second->file_path().compare(file_path.c_str() + failed) == 0) {
975 if (failed)
976 return std::string("!") + it->second->device_path();
977 else
978 return it->second->device_path();
979 }
980 }
981 return EmptyString();
982 }
983
984 // Finds system path prefix from |system_path|
985 const std::string& FindSystemPathPrefix(const std::string& system_path) {
986 if (system_path.empty())
987 return EmptyString();
988 for (SystemPathPrefixSet::const_iterator it = system_path_prefixes_.begin();
989 it != system_path_prefixes_.end();
990 ++it) {
991 if (system_path.find(*it, 0) == 0)
992 return *it;
993 }
994 return EmptyString();
995 }
996
997 // A function to be used as an empty callback
998 static void DoNothing() {
999 }
1000
1001 // Mount event change observers.
1002 ObserverList<Observer> observers_;
1003
1004 scoped_ptr<CrosDisksDBusProxy> dbus_proxy_;
1005
1006 // The list of disks found.
1007 CrosDisksClient::DiskMap disks_;
1008
1009 CrosDisksClient::MountPointMap mount_points_;
1010
1011 typedef std::set<std::string> SystemPathPrefixSet;
1012 SystemPathPrefixSet system_path_prefixes_;
1013
1014 // Set of devices that are supposed to be formated, but are currently waiting
1015 // to be unmounted. When device is in this map, the formatting process HAVEN'T
1016 // started yet.
1017 PathMap formatting_pending_;
1018
1019 base::WeakPtrFactory<CrosDisksClientImpl> weak_ptr_factory_;
1020
1021 DISALLOW_COPY_AND_ASSIGN(CrosDisksClientImpl);
1022 };
1023
1024 // A stub implementaion of CrosDisksClient
1025 class CrosDisksClientStubImpl : public CrosDisksClient {
1026 public:
1027 CrosDisksClientStubImpl() {}
1028 virtual ~CrosDisksClientStubImpl() {}
1029
1030 // CrosDisksClient overrides.
1031 virtual void AddObserver(Observer* observer) OVERRIDE {}
1032 virtual void RemoveObserver(Observer* observer) OVERRIDE {}
1033 virtual const DiskMap& disks() const OVERRIDE { return disks_; }
1034 virtual const MountPointMap& mount_points() const OVERRIDE {
1035 return mount_points_;
1036 }
1037 virtual void RequestMountInfoRefresh() OVERRIDE {}
1038 virtual void MountPath(const std::string& source_path,
1039 MountType type,
1040 const MountPathOptions& options) OVERRIDE {}
1041 virtual void UnmountPath(const std::string& mount_path) OVERRIDE {}
1042 virtual void GetSizeStatsOnFileThread(const std::string& mount_path,
1043 size_t* total_size_kb,
1044 size_t* remaining_size_kb) OVERRIDE {}
1045 virtual void FormatUnmountedDevice(const std::string& device_path) OVERRIDE {}
1046 virtual void FormatMountedDevice(const std::string& mount_path) OVERRIDE {}
1047 virtual void UnmountDeviceRecursive(
1048 const std::string& device_path,
1049 UnmountDeviceRecursiveCallbackType callback,
1050 void* user_data) OVERRIDE {}
1051 private:
1052 DiskMap disks_; // The list of disks found.
1053 MountPointMap mount_points_;
1054
1055 DISALLOW_COPY_AND_ASSIGN(CrosDisksClientStubImpl);
1056 };
1057
1058 } // namespace
1059
1060 // static
1061 std::string CrosDisksClient::MountTypeToString(MountType type) {
1062 switch (type) {
1063 case MOUNT_TYPE_DEVICE:
1064 return "device";
1065 case MOUNT_TYPE_ARCHIVE:
1066 return "file";
1067 case MOUNT_TYPE_NETWORK_STORAGE:
1068 return "network";
1069 case MOUNT_TYPE_INVALID:
1070 return "invalid";
1071 default:
1072 NOTREACHED();
1073 }
1074 return EmptyString();
1075 }
1076
1077 // static
1078 std::string CrosDisksClient::MountConditionToString(MountCondition condition) {
1079 switch (condition) {
1080 case MOUNT_CONDITION_NONE:
1081 return EmptyString();
1082 case MOUNT_CONDITION_UNKNOWN_FILESYSTEM:
1083 return "unknown_filesystem";
1084 case MOUNT_CONDITION_UNSUPPORTED_FILESYSTEM:
1085 return "unsupported_filesystem";
1086 default:
1087 NOTREACHED();
1088 }
1089 return EmptyString();
1090 }
1091
1092 // static
1093 MountType CrosDisksClient::MountTypeFromString(const std::string& type_str) {
1094 if (type_str == "device")
1095 return MOUNT_TYPE_DEVICE;
1096 else if (type_str == "network")
1097 return MOUNT_TYPE_NETWORK_STORAGE;
1098 else if (type_str == "file")
1099 return MOUNT_TYPE_ARCHIVE;
1100 else
1101 return MOUNT_TYPE_INVALID;
1102 }
1103
1104 CrosDisksClient::Disk::Disk(const std::string& device_path,
1105 const std::string& mount_path,
1106 const std::string& system_path,
1107 const std::string& file_path,
1108 const std::string& device_label,
1109 const std::string& drive_label,
1110 const std::string& parent_path,
1111 const std::string& system_path_prefix,
1112 DeviceType device_type,
1113 uint64 total_size,
1114 bool is_parent,
1115 bool is_read_only,
1116 bool has_media,
1117 bool on_boot_device,
1118 bool is_hidden)
1119 : device_path_(device_path),
1120 mount_path_(mount_path),
1121 system_path_(system_path),
1122 file_path_(file_path),
1123 device_label_(device_label),
1124 drive_label_(drive_label),
1125 parent_path_(parent_path),
1126 system_path_prefix_(system_path_prefix),
1127 device_type_(device_type),
1128 total_size_(total_size),
1129 is_parent_(is_parent),
1130 is_read_only_(is_read_only),
1131 has_media_(has_media),
1132 on_boot_device_(on_boot_device),
1133 is_hidden_(is_hidden) {
1134 }
1135
1136 CrosDisksClient::Disk::~Disk() {}
1137
1138 // static
1139 CrosDisksClient* CrosDisksClient::Create(dbus::Bus* bus) {
1140 CrosDisksClient* impl;
1141 if (system::runtime_environment::IsRunningOnChromeOS())
1142 impl = new CrosDisksClientImpl(bus);
1143 else
1144 impl = new CrosDisksClientStubImpl();
1145 return impl;
1146 }
1147
1148 } // namespace chromeos
OLDNEW
« no previous file with comments | « chrome/browser/chromeos/dbus/cros_disks_client.h ('k') | chrome/browser/chromeos/dbus/dbus_thread_manager.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698