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

Side by Side Diff: chrome/browser/chromeos/cros/mount_library.cc

Issue 8386031: Move chromeos_mount.cc from libcros to Chrome tree (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Cleaned up format 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/cros/mount_library.h"
6
7 #include <set>
8 #include <sys/statvfs.h>
9 #include <vector>
10
11 #include "base/message_loop.h"
12 #include "base/string_util.h"
13 #include "chrome/browser/chromeos/cros/cros_library.h"
14 #include "content/public/browser/browser_thread.h"
15
16 using content::BrowserThread;
17
18 const char* kLibraryNotLoaded = "Cros Library not loaded";
19 const char* kDeviceNotFound = "Device could not be found";
20
21 namespace chromeos {
22
23 // static
24 std::string MountLibrary::MountTypeToString(MountType type) {
25 switch (type) {
26 case MOUNT_TYPE_DEVICE:
27 return "device";
28 case MOUNT_TYPE_ARCHIVE:
29 return "file";
30 case MOUNT_TYPE_NETWORK_STORAGE:
31 return "network";
32 case MOUNT_TYPE_INVALID:
33 return "invalid";
34 default:
35 NOTREACHED();
36 }
37 return "";
38 }
39
40 std::string MountLibrary::MountConditionToString(MountCondition condition) {
41 switch (condition) {
42 case MOUNT_CONDITION_NONE:
43 return "";
44 case MOUNT_CONDITION_UNKNOWN_FILESYSTEM:
45 return "unknown_filesystem";
46 case MOUNT_CONDITION_UNSUPPORTED_FILESYSTEM:
47 return "unsupported_filesystem";
48 default:
49 NOTREACHED();
50 }
51 return "";
52 }
53
54 // static
55 MountType MountLibrary::MountTypeFromString(
56 const std::string& type_str) {
57 if (type_str == "device") {
58 return MOUNT_TYPE_DEVICE;
59 } else if (type_str == "network") {
60 return MOUNT_TYPE_NETWORK_STORAGE;
61 } else if (type_str == "file") {
62 return MOUNT_TYPE_ARCHIVE;
63 } else {
64 return MOUNT_TYPE_INVALID;
65 }
66 }
67
68 MountLibrary::Disk::Disk(const std::string& device_path,
69 const std::string& mount_path,
70 const std::string& system_path,
71 const std::string& file_path,
72 const std::string& device_label,
73 const std::string& drive_label,
74 const std::string& parent_path,
75 const std::string& system_path_prefix,
76 DeviceType device_type,
77 uint64 total_size,
78 bool is_parent,
79 bool is_read_only,
80 bool has_media,
81 bool on_boot_device,
82 bool is_hidden)
83 : device_path_(device_path),
84 mount_path_(mount_path),
85 system_path_(system_path),
86 file_path_(file_path),
87 device_label_(device_label),
88 drive_label_(drive_label),
89 parent_path_(parent_path),
90 system_path_prefix_(system_path_prefix),
91 device_type_(device_type),
92 total_size_(total_size),
93 is_parent_(is_parent),
94 is_read_only_(is_read_only),
95 has_media_(has_media),
96 on_boot_device_(on_boot_device),
97 is_hidden_(is_hidden) {
98 }
99
100 MountLibrary::Disk::~Disk() {}
101
102 class MountLibcrosProxyImpl : public MountLibcrosProxy {
103 public:
104 virtual void CallMountPath(const char* source_path,
105 MountType type,
106 const MountPathOptions& options,
107 MountCompletedMonitor callback,
108 void* object) OVERRIDE {
109 chromeos::MountSourcePath(source_path, type, options, callback, object);
110 }
111
112 virtual void CallUnmountPath(const char* path,
113 UnmountRequestCallback callback,
114 void* object) OVERRIDE {
115 chromeos::UnmountMountPoint(path, callback, object);
116 }
117
118 virtual void CallRequestMountInfo(RequestMountInfoCallback callback,
119 void* object) OVERRIDE {
120 chromeos::RequestMountInfo(callback, object);
121 }
122
123 virtual void CallFormatDevice(const char* file_path,
124 const char* filesystem,
125 FormatRequestCallback callback,
126 void* object) OVERRIDE {
127 chromeos::FormatDevice(file_path, filesystem, callback, object);
128 }
129
130 virtual void CallGetDiskProperties(const char* device_path,
131 GetDiskPropertiesCallback callback,
132 void* object) OVERRIDE {
133 chromeos::GetDiskProperties(device_path, callback, object);
134 }
135
136 virtual MountEventConnection MonitorCrosDisks(
137 MountEventMonitor monitor,
138 MountCompletedMonitor mount_completed_monitor,
139 void* object) OVERRIDE {
140 return chromeos::MonitorAllMountEvents(
141 monitor, mount_completed_monitor, object);
142 }
143
144 virtual void DisconnectCrosDisksMonitorIfSet(
145 MountEventConnection conn) OVERRIDE {
146 if (conn)
147 chromeos::DisconnectMountEventMonitor(conn);
148 }
149 };
150
151 class MountLibraryImpl : public MountLibrary {
152
153 struct UnmountDeviceRecursiveCallbackData {
154 MountLibraryImpl* const object;
155 void* user_data;
156 UnmountDeviceRecursiveCallbackType callback;
157 size_t pending_callbacks_count;
158 bool success;
159
160 UnmountDeviceRecursiveCallbackData(MountLibraryImpl* const o, void* ud,
161 UnmountDeviceRecursiveCallbackType cb, int count)
162 : object(o),
163 user_data(ud),
164 callback(cb),
165 pending_callbacks_count(count),
166 success(true) {
167 }
168 };
169
170 public:
171 MountLibraryImpl() : libcros_proxy_(new MountLibcrosProxyImpl()),
172 mount_status_connection_(NULL) {
173 }
174
175 virtual ~MountLibraryImpl() {
176 libcros_proxy_->DisconnectCrosDisksMonitorIfSet(
177 mount_status_connection_);
178 }
179
180 // MountLibrary overrides.
181 virtual void Init() OVERRIDE {
182 DCHECK(CrosLibrary::Get()->libcros_loaded());
183 // Getting the monitor status so that the daemon starts up.
184 mount_status_connection_ = libcros_proxy_->MonitorCrosDisks(
185 &MonitorMountEventsHandler, &MountCompletedHandler, this);
186 }
187
188 virtual void AddObserver(Observer* observer) OVERRIDE {
189 observers_.AddObserver(observer);
190 }
191
192 virtual void RemoveObserver(Observer* observer) OVERRIDE {
193 observers_.RemoveObserver(observer);
194 }
195
196 virtual void MountPath(const char* source_path,
197 MountType type,
198 const MountPathOptions& options) OVERRIDE {
199 // Hidden and non-existent devices should not be mounted.
200 if (type == MOUNT_TYPE_DEVICE) {
201 DiskMap::const_iterator it = disks_.find(source_path);
202 if (it == disks_.end() || it->second->is_hidden()) {
203 MountCompletedHandler(this, MOUNT_ERROR_INTERNAL, source_path, type,
204 NULL);
205 return;
206 }
207 }
208 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
209 libcros_proxy_->CallMountPath(source_path, type, options,
210 &MountCompletedHandler, this);
211 }
212
213 virtual void UnmountPath(const char* mount_path) OVERRIDE {
214 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
215 libcros_proxy_->CallUnmountPath(mount_path, &UnmountMountPointCallback,
216 this);
217 }
218
219 virtual void GetSizeStatsOnFileThread(const char* mount_path,
220 size_t* total_size_kb, size_t* remaining_size_kb) OVERRIDE {
221 CHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
222
223 uint64_t total_size_uint64 = 0;
224 uint64_t remaining_size_uint64 = 0;
225
226 struct statvfs stat;
227 if (statvfs(mount_path, &stat) == 0) {
228 total_size_uint64 =
229 static_cast<uint64_t>(stat.f_blocks) * stat.f_frsize;
230 remaining_size_uint64 =
231 static_cast<uint64_t>(stat.f_bfree) * stat.f_frsize;
232 }
233
234 *total_size_kb = static_cast<size_t>(total_size_uint64 / 1024);
235 *remaining_size_kb = static_cast<size_t>(remaining_size_uint64 / 1024);
236 }
237
238 virtual void FormatUnmountedDevice(const char* file_path) OVERRIDE {
239 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
240 for (MountLibrary::DiskMap::iterator it = disks_.begin();
241 it != disks_.end(); ++it) {
242 if (it->second->file_path().compare(file_path) == 0 &&
243 !it->second->mount_path().empty()) {
244 OnFormatDevice(file_path,
245 false,
246 MOUNT_METHOD_ERROR_LOCAL,
247 "Device is still mounted.");
248 return;
249 }
250 }
251 libcros_proxy_->CallFormatDevice(file_path, "vfat", &FormatDeviceCallback,
252 this);
253 }
254
255 virtual void FormatMountedDevice(const char* mount_path) OVERRIDE {
256 DCHECK(mount_path);
257 Disk* disk = NULL;
258 for (MountLibrary::DiskMap::iterator it = disks_.begin();
259 it != disks_.end(); ++it) {
260 if (it->second->mount_path().compare(mount_path) == 0) {
261 disk = it->second;
262 break;
263 }
264 }
265 if (!disk) {
266 OnFormatDevice(mount_path,
267 false,
268 MOUNT_METHOD_ERROR_LOCAL,
269 "Device with this mount path not found.");
270 return;
271 }
272
273 if (formatting_pending_.find(disk->device_path()) !=
274 formatting_pending_.end()) {
275 OnFormatDevice(mount_path,
276 false,
277 MOUNT_METHOD_ERROR_LOCAL,
278 "Formatting is already pending.");
279 return;
280 }
281 // Formatting process continues, after unmounting.
282 formatting_pending_[disk->device_path()] = disk->file_path();
283 UnmountPath(disk->mount_path().c_str());
284 }
285
286 virtual void UnmountDeviceRecursive(const char* device_path,
287 UnmountDeviceRecursiveCallbackType callback, void* user_data)
288 OVERRIDE {
289 bool success = true;
290 const char* error_message = NULL;
291 std::vector<const char*> devices_to_unmount;
292
293 // Get list of all devices to unmount.
294 int device_path_len = strlen(device_path);
295 for (DiskMap::iterator it = disks_.begin(); it != disks_.end(); ++it) {
296 if (!it->second->mount_path().empty() &&
297 strncmp(device_path, it->second->device_path().c_str(),
298 device_path_len) == 0) {
299 devices_to_unmount.push_back(it->second->mount_path().c_str());
300 }
301 }
302
303 // We should detect at least original device.
304 if (devices_to_unmount.size() == 0) {
305 if (disks_.find(device_path) == disks_.end()) {
306 success = false;
307 error_message = kDeviceNotFound;
308 } else {
309 // Nothing to unmount.
310 callback(user_data, true);
311 return;
312 }
313 }
314
315 if (success) {
316 // We will send the same callback data object to all Unmount calls and use
317 // it to syncronize callbacks.
318 UnmountDeviceRecursiveCallbackData*
319 cb_data = new UnmountDeviceRecursiveCallbackData(this, user_data,
320 callback, devices_to_unmount.size());
321 for (std::vector<const char*>::iterator it = devices_to_unmount.begin();
322 it != devices_to_unmount.end();
323 ++it) {
324 libcros_proxy_->CallUnmountPath(*it, &UnmountDeviceRecursiveCallback,
325 cb_data);
326 }
327 } else {
328 LOG(WARNING) << "Unmount recursive request failed for device "
329 << device_path << ", with error: " << error_message;
330 callback(user_data, false);
331 }
332 }
333
334 virtual void RequestMountInfoRefresh() OVERRIDE {
335 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
336 libcros_proxy_->CallRequestMountInfo(RequestMountInfoCallback, this);
337 }
338
339 const DiskMap& disks() const OVERRIDE { return disks_; }
340 const MountPointMap& mount_points() const OVERRIDE { return mount_points_; }
341
342 virtual void SetLibcrosProxy(MountLibcrosProxy* proxy) OVERRIDE {
343 libcros_proxy_->DisconnectCrosDisksMonitorIfSet(mount_status_connection_);
344 libcros_proxy_.reset(proxy);
345 mount_status_connection_ = libcros_proxy_->MonitorCrosDisks(
346 &MonitorMountEventsHandler, &MountCompletedHandler, this);
347 }
348 private:
349 // Callback for MountComplete signal and MountSourcePath method.
350 static void MountCompletedHandler(void* object,
351 MountError error_code,
352 const char* source_path,
353 MountType type,
354 const char* mount_path) {
355 DCHECK(object);
356 MountCondition mount_condition = MOUNT_CONDITION_NONE;
357 if (type == MOUNT_TYPE_DEVICE) {
358 if (error_code == MOUNT_ERROR_UNKNOWN_FILESYSTEM)
359 mount_condition = MOUNT_CONDITION_UNKNOWN_FILESYSTEM;
360 if (error_code == MOUNT_ERROR_UNSUPORTED_FILESYSTEM)
361 mount_condition = MOUNT_CONDITION_UNSUPPORTED_FILESYSTEM;
362 }
363
364 MountLibraryImpl* self = static_cast<MountLibraryImpl*>(object);
365 self->OnMountCompleted(static_cast<MountError>(error_code),
366 MountPointInfo(source_path,
367 mount_path,
368 type,
369 mount_condition));
370 }
371
372 // Callback for UnmountRemovableDevice method.
373 static void UnmountMountPointCallback(void* object,
374 const char* mount_path,
375 MountMethodErrorType error,
376 const char* error_message) {
377 DCHECK(object);
378 MountLibraryImpl* self = static_cast<MountLibraryImpl*>(object);
379 self->OnUnmountPath(mount_path, error, error_message);
380 }
381
382 // Callback for FormatRemovableDevice method.
383 static void FormatDeviceCallback(void* object,
384 const char* file_path,
385 bool success,
386 MountMethodErrorType error,
387 const char* error_message) {
388 DCHECK(object);
389 MountLibraryImpl* self = static_cast<MountLibraryImpl*>(object);
390 const char* device_path = self->FilePathToDevicePath(file_path);
391 if (!device_path) {
392 LOG(ERROR) << "Error while handling disks metadata. Cannot find "
393 << "device that is being formatted.";
394 return;
395 }
396 self->OnFormatDevice(device_path, success, error, error_message);
397 }
398
399 // Callback for UnmountDeviceRecursive.
400 static void UnmountDeviceRecursiveCallback(void* object,
401 const char* mount_path,
402 MountMethodErrorType error,
403 const char* error_message) {
404 DCHECK(object);
405 UnmountDeviceRecursiveCallbackData* cb_data =
406 static_cast<UnmountDeviceRecursiveCallbackData*>(object);
407
408 // Do standard processing for Unmount event.
409 cb_data->object->OnUnmountPath(mount_path,
410 error,
411 error_message);
412 if (error == MOUNT_METHOD_ERROR_LOCAL) {
413 cb_data->success = false;
414 } else if (error == MOUNT_METHOD_ERROR_NONE) {
415 LOG(INFO) << mount_path << " unmounted.";
416 }
417
418 // This is safe as long as all callbacks are called on the same thread as
419 // UnmountDeviceRecursive.
420 cb_data->pending_callbacks_count--;
421
422 if (cb_data->pending_callbacks_count == 0) {
423 cb_data->callback(cb_data->user_data, cb_data->success);
424 delete cb_data;
425 }
426 }
427
428 // Callback for disk information retrieval calls.
429 static void GetDiskPropertiesCallback(void* object,
430 const char* device_path,
431 const DiskInfo* disk,
432 MountMethodErrorType error,
433 const char* error_message) {
434 DCHECK(object);
435 MountLibraryImpl* self = static_cast<MountLibraryImpl*>(object);
436 self->OnGetDiskProperties(device_path,
437 disk,
438 error,
439 error_message);
440 }
441
442 // Callback for RequestMountInfo call.
443 static void RequestMountInfoCallback(void* object,
444 const char** devices,
445 size_t device_len,
446 MountMethodErrorType error,
447 const char* error_message) {
448 DCHECK(object);
449 MountLibraryImpl* self = static_cast<MountLibraryImpl*>(object);
450 self->OnRequestMountInfo(devices,
451 device_len,
452 error,
453 error_message);
454 }
455
456 // This method will receive events that are caused by drive status changes.
457 static void MonitorMountEventsHandler(void* object,
458 MountEventType evt,
459 const char* device_path) {
460 DCHECK(object);
461 MountLibraryImpl* self = static_cast<MountLibraryImpl*>(object);
462 self->OnMountEvent(evt, device_path);
463 }
464
465
466 void OnMountCompleted(MountError error_code,
467 const MountPointInfo& mount_info) {
468 DCHECK(!mount_info.source_path.empty());
469
470 FireMountCompleted(MOUNTING, error_code, mount_info);
471
472 // If the device is corrupted but it's still possible to format it, it will
473 // be fake mounted.
474 if ((error_code == MOUNT_ERROR_NONE || mount_info.mount_condition) &&
475 mount_points_.find(mount_info.mount_path) == mount_points_.end()) {
476 mount_points_.insert(MountPointMap::value_type(
477 mount_info.mount_path.c_str(),
478 mount_info));
479 }
480
481 if ((error_code == MOUNT_ERROR_NONE || mount_info.mount_condition) &&
482 mount_info.mount_type == MOUNT_TYPE_DEVICE &&
483 !mount_info.source_path.empty() &&
484 !mount_info.mount_path.empty()) {
485 DiskMap::iterator iter = disks_.find(mount_info.source_path);
486 if (iter == disks_.end()) {
487 // disk might have been removed by now?
488 return;
489 }
490 Disk* disk = iter->second;
491 DCHECK(disk);
492 disk->set_mount_path(mount_info.mount_path.c_str());
493 FireDiskStatusUpdate(MOUNT_DISK_MOUNTED, disk);
494 }
495 }
496
497 void OnUnmountPath(const char* mount_path,
498 MountMethodErrorType error,
499 const char* error_message) {
500 DCHECK(mount_path);
501 if (error == MOUNT_METHOD_ERROR_NONE && mount_path) {
502 MountPointMap::iterator mount_points_it = mount_points_.find(mount_path);
503 if (mount_points_it == mount_points_.end())
504 return;
505 // TODO(tbarzic): Add separate, PathUnmounted event to Observer.
506 FireMountCompleted(
507 UNMOUNTING,
508 MOUNT_ERROR_NONE,
509 MountPointInfo(mount_points_it->second.source_path.c_str(),
510 mount_points_it->second.mount_path.c_str(),
511 mount_points_it->second.mount_type,
512 mount_points_it->second.mount_condition));
513 std::string path(mount_points_it->second.source_path);
514 mount_points_.erase(mount_points_it);
515 DiskMap::iterator iter = disks_.find(path);
516 if (iter == disks_.end()) {
517 // disk might have been removed by now.
518 return;
519 }
520 Disk* disk = iter->second;
521 DCHECK(disk);
522 disk->clear_mount_path();
523 // Check if there is a formatting scheduled
524 PathMap::iterator it = formatting_pending_.find(disk->device_path());
525 if (it != formatting_pending_.end()) {
526 const std::string file_path = it->second;
527 formatting_pending_.erase(it);
528 FormatUnmountedDevice(file_path.c_str());
529 }
530 } else {
531 LOG(WARNING) << "Unmount request failed for device "
532 << mount_path << ", with error: "
533 << (error_message ? error_message : "Unknown");
534 }
535 }
536
537 void OnFormatDevice(const char* device_path,
538 bool success,
539 MountMethodErrorType error,
540 const char* error_message) {
541 DCHECK(device_path);
542 if (error == MOUNT_METHOD_ERROR_NONE && device_path && success) {
543 FireDeviceStatusUpdate(MOUNT_FORMATTING_STARTED, device_path);
544 } else {
545 FireDeviceStatusUpdate(MOUNT_FORMATTING_STARTED,
546 std::string("!") + device_path);
547 LOG(WARNING) << "Format request failed for device "
548 << device_path << ", with error: "
549 << (error_message ? error_message : "Unknown");
550 }
551 }
552
553 void OnGetDiskProperties(const char* device_path,
554 const DiskInfo* disk,
555 MountMethodErrorType error,
556 const char* error_message) {
557 DCHECK(device_path);
558 if (error == MOUNT_METHOD_ERROR_NONE && device_path) {
559 // TODO(zelidrag): Find a better way to filter these out before we
560 // fetch the properties:
561 // Ignore disks coming from the device we booted the system from.
562
563 // This cast is temporal solution, until we merge DiskInfo and
564 // DiskInfoAdvanced into single interface.
565 if (disk->on_boot_device())
566 return;
567
568 LOG(WARNING) << "Found disk " << device_path;
569 // Delete previous disk info for this path:
570 bool is_new = true;
571 std::string device_path_string(device_path);
572 DiskMap::iterator iter = disks_.find(device_path_string);
573 if (iter != disks_.end()) {
574 delete iter->second;
575 disks_.erase(iter);
576 is_new = false;
577 }
578
579 std::string path;
580 std::string mountpath;
581 std::string systempath;
582 std::string filepath;
583 std::string devicelabel;
584 std::string drivelabel;
585 std::string parentpath;
586
587 if (disk->path() != NULL)
588 path = disk->path();
589
590 if (disk->mount_path() != NULL)
591 mountpath = disk->mount_path();
592
593 if (disk->system_path() != NULL)
594 systempath = disk->system_path();
595
596 if (disk->file_path() != NULL)
597 filepath = disk->file_path();
598
599 if (disk->label() != NULL)
600 devicelabel = disk->label();
601
602 if (disk->drive_label() != NULL)
603 drivelabel = disk->drive_label();
604
605 if (disk->partition_slave() != NULL)
606 parentpath = disk->partition_slave();
607
608 Disk* new_disk = new Disk(path,
609 mountpath,
610 systempath,
611 filepath,
612 devicelabel,
613 drivelabel,
614 parentpath,
615 FindSystemPathPrefix(systempath),
616 disk->device_type(),
617 disk->size(),
618 disk->is_drive(),
619 disk->is_read_only(),
620 disk->has_media(),
621 disk->on_boot_device(),
622 disk->is_hidden());
623 disks_.insert(
624 std::pair<std::string, Disk*>(device_path_string, new_disk));
625 FireDiskStatusUpdate(is_new ? MOUNT_DISK_ADDED : MOUNT_DISK_CHANGED,
626 new_disk);
627 } else {
628 LOG(WARNING) << "Property retrieval request failed for device "
629 << device_path << ", with error: "
630 << (error_message ? error_message : "Unknown");
631 }
632 }
633
634 void OnRequestMountInfo(const char** devices,
635 size_t devices_len,
636 MountMethodErrorType error,
637 const char* error_message) {
638 std::set<std::string> current_device_set;
639 if (error == MOUNT_METHOD_ERROR_NONE && devices && devices_len) {
640 // Initiate properties fetch for all removable disks,
641 bool found_disk = false;
642 for (size_t i = 0; i < devices_len; i++) {
643 if (!devices[i]) {
644 NOTREACHED();
645 continue;
646 }
647 current_device_set.insert(std::string(devices[i]));
648 found_disk = true;
649 // Initiate disk property retrieval for each relevant device path.
650 libcros_proxy_->CallGetDiskProperties(devices[i],
651 &GetDiskPropertiesCallback, this);
652 }
653 } else if (error != MOUNT_METHOD_ERROR_NONE) {
654 LOG(WARNING) << "Request mount info retrieval request failed with error: "
655 << (error_message ? error_message : "Unknown");
656 }
657 // Search and remove disks that are no longer present.
658 for (MountLibrary::DiskMap::iterator iter = disks_.begin();
659 iter != disks_.end(); ) {
660 if (current_device_set.find(iter->first) == current_device_set.end()) {
661 Disk* disk = iter->second;
662 FireDiskStatusUpdate(MOUNT_DISK_REMOVED, disk);
663 delete iter->second;
664 disks_.erase(iter++);
665 } else {
666 ++iter;
667 }
668 }
669 }
670
671 void OnMountEvent(MountEventType evt,
672 const char* device_path) {
673 if (!device_path)
674 return;
675 MountLibraryEventType type = MOUNT_DEVICE_ADDED;
676 switch (evt) {
677 case DISK_ADDED: {
678 libcros_proxy_->CallGetDiskProperties(device_path,
679 &MountLibraryImpl::GetDiskPropertiesCallback, this);
680 return;
681 }
682 case DISK_REMOVED: {
683 // Search and remove disks that are no longer present.
684 MountLibrary::DiskMap::iterator iter =
685 disks_.find(std::string(device_path));
686 if (iter != disks_.end()) {
687 Disk* disk = iter->second;
688 FireDiskStatusUpdate(MOUNT_DISK_REMOVED, disk);
689 delete iter->second;
690 disks_.erase(iter);
691 }
692 return;
693 }
694 case DEVICE_ADDED: {
695 type = MOUNT_DEVICE_ADDED;
696 system_path_prefixes_.insert(device_path);
697 break;
698 }
699 case DEVICE_REMOVED: {
700 type = MOUNT_DEVICE_REMOVED;
701 system_path_prefixes_.erase(device_path);
702 break;
703 }
704 case DEVICE_SCANNED: {
705 type = MOUNT_DEVICE_SCANNED;
706 break;
707 }
708 case FORMATTING_FINISHED: {
709 // FORMATTING_FINISHED actually returns file path instead of device
710 // path.
711 device_path = FilePathToDevicePath(device_path);
712 if (!device_path) {
713 LOG(ERROR) << "Error while handling disks metadata. Cannot find "
714 << "device that is being formatted.";
715 return;
716 }
717 type = MOUNT_FORMATTING_FINISHED;
718 break;
719 }
720 default: {
721 return;
722 }
723 }
724 FireDeviceStatusUpdate(type, std::string(device_path));
725 }
726
727 void FireDiskStatusUpdate(MountLibraryEventType evt,
728 const Disk* disk) {
729 // Make sure we run on UI thread.
730 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
731 FOR_EACH_OBSERVER(
732 Observer, observers_, DiskChanged(evt, disk));
733 }
734
735 void FireDeviceStatusUpdate(MountLibraryEventType evt,
736 const std::string& device_path) {
737 // Make sure we run on UI thread.
738 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
739 FOR_EACH_OBSERVER(
740 Observer, observers_, DeviceChanged(evt, device_path));
741 }
742
743 void FireMountCompleted(MountEvent event_type,
744 MountError error_code,
745 const MountPointInfo& mount_info) {
746 // Make sure we run on UI thread.
747 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
748 FOR_EACH_OBSERVER(
749 Observer, observers_, MountCompleted(event_type,
750 error_code,
751 mount_info));
752 }
753
754 const char* FilePathToDevicePath(const char* file_path) {
755 int failed = (file_path[0] == '!') ? 1 : 0;
756 for (MountLibrary::DiskMap::iterator it = disks_.begin();
757 it != disks_.end(); ++it) {
758 if (it->second->file_path().compare(file_path + failed) == 0) {
759 if (failed) {
760 return (std::string("!") + it->second->device_path()).c_str();
761 } else {
762 return it->second->device_path().c_str();
763 }
764 }
765 }
766 return NULL;
767 }
768
769 const std::string& FindSystemPathPrefix(const std::string& system_path) {
770 if (system_path.empty())
771 return EmptyString();
772 for (SystemPathPrefixSet::const_iterator it = system_path_prefixes_.begin();
773 it != system_path_prefixes_.end();
774 ++it) {
775 if (system_path.find(*it, 0) == 0)
776 return *it;
777 }
778 return EmptyString();
779 }
780
781 // Mount event change observers.
782 ObserverList<Observer> observers_;
783
784 scoped_ptr<MountLibcrosProxy> libcros_proxy_;
785
786 // A reference to the mount api, to allow callbacks when the mount
787 // status changes.
788 MountEventConnection mount_status_connection_;
789
790 // The list of disks found.
791 MountLibrary::DiskMap disks_;
792
793 MountLibrary::MountPointMap mount_points_;
794
795 typedef std::set<std::string> SystemPathPrefixSet;
796 SystemPathPrefixSet system_path_prefixes_;
797
798 // Set of devices that are supposed to be formated, but are currently waiting
799 // to be unmounted. When device is in this map, the formatting process HAVEN'T
800 // started yet.
801 PathMap formatting_pending_;
802
803 DISALLOW_COPY_AND_ASSIGN(MountLibraryImpl);
804 };
805
806 class MountLibraryStubImpl : public MountLibrary {
807 public:
808 MountLibraryStubImpl() {}
809 virtual ~MountLibraryStubImpl() {}
810
811 // MountLibrary overrides.
812 virtual void Init() OVERRIDE {}
813 virtual void AddObserver(Observer* observer) OVERRIDE {}
814 virtual void RemoveObserver(Observer* observer) OVERRIDE {}
815 virtual const DiskMap& disks() const OVERRIDE { return disks_; }
816 virtual const MountPointMap& mount_points() const OVERRIDE {
817 return mount_points_;
818 }
819 virtual void RequestMountInfoRefresh() OVERRIDE {}
820 virtual void MountPath(const char* source_path, MountType type,
821 const MountPathOptions& options) OVERRIDE {}
822 virtual void UnmountPath(const char* mount_path) OVERRIDE {}
823 virtual void GetSizeStatsOnFileThread(const char* mount_path,
824 size_t* total_size_kb, size_t* remaining_size_kb) OVERRIDE {}
825 virtual void FormatUnmountedDevice(const char* device_path) OVERRIDE {}
826 virtual void FormatMountedDevice(const char* mount_path) OVERRIDE {}
827 virtual void UnmountDeviceRecursive(const char* device_path,
828 UnmountDeviceRecursiveCallbackType callback, void* user_data)
829 OVERRIDE {}
830 private:
831 // The list of disks found.
832 DiskMap disks_;
833 MountPointMap mount_points_;
834
835 DISALLOW_COPY_AND_ASSIGN(MountLibraryStubImpl);
836 };
837
838 // static
839 MountLibrary* MountLibrary::GetImpl(bool stub) {
840 MountLibrary* impl;
841 if (stub)
842 impl = new MountLibraryStubImpl();
843 else
844 impl = new MountLibraryImpl();
845 impl->Init();
846 return impl;
847 }
848
849 } // namespace chromeos
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698