Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / chromeos / file_manager / volume_manager.cc
1 // Copyright 2013 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/file_manager/volume_manager.h"
6
7 #include "base/basictypes.h"
8 #include "base/bind.h"
9 #include "base/callback.h"
10 #include "base/command_line.h"
11 #include "base/files/file_path.h"
12 #include "base/logging.h"
13 #include "base/memory/singleton.h"
14 #include "base/prefs/pref_service.h"
15 #include "chrome/browser/chromeos/drive/drive_integration_service.h"
16 #include "chrome/browser/chromeos/drive/file_errors.h"
17 #include "chrome/browser/chromeos/drive/file_system_interface.h"
18 #include "chrome/browser/chromeos/drive/file_system_util.h"
19 #include "chrome/browser/chromeos/file_manager/mounted_disk_monitor.h"
20 #include "chrome/browser/chromeos/file_manager/path_util.h"
21 #include "chrome/browser/chromeos/file_manager/volume_manager_factory.h"
22 #include "chrome/browser/chromeos/file_manager/volume_manager_observer.h"
23 #include "chrome/browser/chromeos/profiles/profile_helper.h"
24 #include "chrome/browser/local_discovery/storage/privet_filesystem_constants.h"
25 #include "chrome/browser/profiles/profile.h"
26 #include "chrome/common/chrome_switches.h"
27 #include "chrome/common/pref_names.h"
28 #include "chromeos/dbus/cros_disks_client.h"
29 #include "chromeos/disks/disk_mount_manager.h"
30 #include "content/public/browser/browser_context.h"
31 #include "content/public/browser/browser_thread.h"
32 #include "webkit/browser/fileapi/external_mount_points.h"
33
34 namespace file_manager {
35 namespace {
36
37 // Registers |path| as the "Downloads" folder to the FileSystem API backend.
38 // If another folder is already mounted. It revokes and overrides the old one.
39 bool RegisterDownloadsMountPoint(Profile* profile, const base::FilePath& path) {
40   // Although we show only profile's own "Downloads" folder in Files.app,
41   // in the backend we need to mount all profile's download directory globally.
42   // Otherwise, Files.app cannot support cross-profile file copies, etc.
43   // For this reason, we need to register to the global GetSystemInstance().
44   const std::string mount_point_name =
45       file_manager::util::GetDownloadsMountPointName(profile);
46   fileapi::ExternalMountPoints* const mount_points =
47       fileapi::ExternalMountPoints::GetSystemInstance();
48
49   // In some tests we want to override existing Downloads mount point, so we
50   // first revoke the existing mount point (if any).
51   mount_points->RevokeFileSystem(mount_point_name);
52   return mount_points->RegisterFileSystem(
53       mount_point_name, fileapi::kFileSystemTypeNativeLocal,
54       fileapi::FileSystemMountOption(), path);
55 }
56
57 // Finds the path register as the "Downloads" folder to FileSystem API backend.
58 // Returns false if it is not registered.
59 bool FindDownloadsMountPointPath(Profile* profile, base::FilePath* path) {
60   const std::string mount_point_name =
61       util::GetDownloadsMountPointName(profile);
62   fileapi::ExternalMountPoints* const mount_points =
63       fileapi::ExternalMountPoints::GetSystemInstance();
64
65   return mount_points->GetRegisteredPath(mount_point_name, path);
66 }
67
68 // Called on completion of MarkCacheFileAsUnmounted.
69 void OnMarkCacheFileAsUnmounted(drive::FileError error) {
70   // Do nothing.
71 }
72
73 VolumeType MountTypeToVolumeType(
74     chromeos::MountType type) {
75   switch (type) {
76     case chromeos::MOUNT_TYPE_INVALID:
77       // We don't expect this value, but list here, so that when any value
78       // is added to the enum definition but this is not edited, the compiler
79       // warns it.
80       break;
81     case chromeos::MOUNT_TYPE_DEVICE:
82       return VOLUME_TYPE_REMOVABLE_DISK_PARTITION;
83     case chromeos::MOUNT_TYPE_ARCHIVE:
84       return VOLUME_TYPE_MOUNTED_ARCHIVE_FILE;
85   }
86
87   NOTREACHED();
88   return VOLUME_TYPE_DOWNLOADS_DIRECTORY;
89 }
90
91 // Returns a string representation of the given volume type.
92 std::string VolumeTypeToString(VolumeType type) {
93   switch (type) {
94     case VOLUME_TYPE_GOOGLE_DRIVE:
95       return "drive";
96     case VOLUME_TYPE_DOWNLOADS_DIRECTORY:
97       return "downloads";
98     case VOLUME_TYPE_REMOVABLE_DISK_PARTITION:
99       return "removable";
100     case VOLUME_TYPE_MOUNTED_ARCHIVE_FILE:
101       return "archive";
102     case VOLUME_TYPE_CLOUD_DEVICE:
103       return "cloud_device";
104   }
105   NOTREACHED();
106   return "";
107 }
108
109 // Generates a unique volume ID for the given volume info.
110 std::string GenerateVolumeId(const VolumeInfo& volume_info) {
111   // For the same volume type, base names are unique, as mount points are
112   // flat for the same volume type.
113   return (VolumeTypeToString(volume_info.type) + ":" +
114           volume_info.mount_path.BaseName().AsUTF8Unsafe());
115 }
116
117 // Returns the VolumeInfo for Drive file system.
118 VolumeInfo CreateDriveVolumeInfo(Profile* profile) {
119   const base::FilePath& drive_path =
120       drive::util::GetDriveMountPointPath(profile);
121
122   VolumeInfo volume_info;
123   volume_info.type = VOLUME_TYPE_GOOGLE_DRIVE;
124   volume_info.device_type = chromeos::DEVICE_TYPE_UNKNOWN;
125   volume_info.source_path = drive_path;
126   volume_info.mount_path = drive_path;
127   volume_info.mount_condition = chromeos::disks::MOUNT_CONDITION_NONE;
128   volume_info.is_parent = false;
129   volume_info.is_read_only = false;
130   volume_info.volume_id = GenerateVolumeId(volume_info);
131   return volume_info;
132 }
133
134 VolumeInfo CreateDownloadsVolumeInfo(
135     const base::FilePath& downloads_path) {
136   VolumeInfo volume_info;
137   volume_info.type = VOLUME_TYPE_DOWNLOADS_DIRECTORY;
138   volume_info.device_type = chromeos::DEVICE_TYPE_UNKNOWN;
139   // Keep source_path empty.
140   volume_info.mount_path = downloads_path;
141   volume_info.mount_condition = chromeos::disks::MOUNT_CONDITION_NONE;
142   volume_info.is_parent = false;
143   volume_info.is_read_only = false;
144   volume_info.volume_id = GenerateVolumeId(volume_info);
145   return volume_info;
146 }
147
148 VolumeInfo CreateVolumeInfoFromMountPointInfo(
149     const chromeos::disks::DiskMountManager::MountPointInfo& mount_point,
150     const chromeos::disks::DiskMountManager::Disk* disk) {
151   VolumeInfo volume_info;
152   volume_info.type = MountTypeToVolumeType(mount_point.mount_type);
153   volume_info.source_path = base::FilePath(mount_point.source_path);
154   volume_info.mount_path = base::FilePath(mount_point.mount_path);
155   volume_info.mount_condition = mount_point.mount_condition;
156   if (disk) {
157     volume_info.device_type = disk->device_type();
158     volume_info.system_path_prefix =
159         base::FilePath(disk->system_path_prefix());
160     volume_info.drive_label = disk->drive_label();
161     volume_info.is_parent = disk->is_parent();
162     volume_info.is_read_only = disk->is_read_only();
163   } else {
164     volume_info.device_type = chromeos::DEVICE_TYPE_UNKNOWN;
165     volume_info.is_parent = false;
166     volume_info.is_read_only =
167         (mount_point.mount_type == chromeos::MOUNT_TYPE_ARCHIVE);
168   }
169   volume_info.volume_id = GenerateVolumeId(volume_info);
170
171   return volume_info;
172 }
173
174 VolumeInfo CreatePrivetVolumeInfo(
175     const local_discovery::PrivetVolumeLister::VolumeInfo& privet_volume_info) {
176   VolumeInfo volume_info;
177   volume_info.type = VOLUME_TYPE_CLOUD_DEVICE;
178   volume_info.mount_path = privet_volume_info.volume_path;
179   volume_info.mount_condition = chromeos::disks::MOUNT_CONDITION_NONE;
180   volume_info.is_parent = true;
181   volume_info.is_read_only = true;
182   volume_info.volume_id = GenerateVolumeId(volume_info);
183   return volume_info;
184 }
185
186 }  // namespace
187
188 VolumeInfo::VolumeInfo() {
189 }
190
191 VolumeInfo::~VolumeInfo() {
192 }
193
194 VolumeManager::VolumeManager(
195     Profile* profile,
196     drive::DriveIntegrationService* drive_integration_service,
197     chromeos::PowerManagerClient* power_manager_client,
198     chromeos::disks::DiskMountManager* disk_mount_manager)
199     : profile_(profile),
200       drive_integration_service_(drive_integration_service),
201       disk_mount_manager_(disk_mount_manager),
202       mounted_disk_monitor_(
203           new MountedDiskMonitor(power_manager_client, disk_mount_manager)) {
204   DCHECK(disk_mount_manager);
205 }
206
207 VolumeManager::~VolumeManager() {
208 }
209
210 VolumeManager* VolumeManager::Get(content::BrowserContext* context) {
211   return VolumeManagerFactory::Get(context);
212 }
213
214 void VolumeManager::Initialize() {
215   const bool kNotRemounting = false;
216
217   // Path to mount user folders have changed several times. We need to migrate
218   // the old preferences on paths to the new format when needed. For the detail,
219   // see the comments in file_manager::util::MigratePathFromOldFormat,
220   // Note: Preferences related to downloads are handled in download_prefs.cc.
221   // TODO(kinaba): Remove this after several rounds of releases.
222   const base::FilePath old_path =
223       profile_->GetPrefs()->GetFilePath(prefs::kSelectFileLastDirectory);
224   base::FilePath new_path;
225   if (!old_path.empty() &&
226       file_manager::util::MigratePathFromOldFormat(profile_,
227                                                    old_path, &new_path)) {
228     profile_->GetPrefs()->SetFilePath(prefs::kSelectFileLastDirectory,
229                                       new_path);
230   }
231
232   // Register 'Downloads' folder for the profile to the file system.
233   if (!chromeos::ProfileHelper::IsSigninProfile(profile_)) {
234     const base::FilePath downloads =
235         file_manager::util::GetDownloadsFolderForProfile(profile_);
236     const bool success = RegisterDownloadsMountPoint(profile_, downloads);
237     DCHECK(success);
238
239     DoMountEvent(chromeos::MOUNT_ERROR_NONE,
240                  CreateDownloadsVolumeInfo(downloads),
241                  kNotRemounting);
242   }
243
244   // Subscribe to DriveIntegrationService.
245   if (drive_integration_service_) {
246     drive_integration_service_->AddObserver(this);
247     if (drive_integration_service_->IsMounted()) {
248       DoMountEvent(chromeos::MOUNT_ERROR_NONE,
249                    CreateDriveVolumeInfo(profile_),
250                    kNotRemounting);
251     }
252   }
253
254   // Subscribe to DiskMountManager.
255   disk_mount_manager_->AddObserver(this);
256
257   std::vector<VolumeInfo> archives;
258
259   const chromeos::disks::DiskMountManager::MountPointMap& mount_points =
260       disk_mount_manager_->mount_points();
261   for (chromeos::disks::DiskMountManager::MountPointMap::const_iterator it =
262            mount_points.begin();
263        it != mount_points.end();
264        ++it) {
265     if (it->second.mount_type == chromeos::MOUNT_TYPE_ARCHIVE) {
266       // Archives are mounted after other type of volumes. See below.
267       archives.push_back(CreateVolumeInfoFromMountPointInfo(it->second, NULL));
268       continue;
269     }
270     DoMountEvent(
271         chromeos::MOUNT_ERROR_NONE,
272         CreateVolumeInfoFromMountPointInfo(
273             it->second,
274             disk_mount_manager_->FindDiskBySourcePath(it->second.source_path)),
275             kNotRemounting);
276   }
277
278   // We mount archives only if they are opened from currently mounted volumes.
279   // To check the condition correctly in DoMountEvent, we care the order.
280   std::vector<bool> done(archives.size(), false);
281   for (size_t i = 0; i < archives.size(); ++i) {
282     if (!done[i]) {
283       std::vector<VolumeInfo> chain;
284       done[i] = true;
285       chain.push_back(archives[i]);
286
287       // If archives[i]'s source_path is in another archive, mount it first.
288       for (size_t parent = 0; parent < archives.size(); ++parent) {
289         if (!done[parent] &&
290             archives[parent].mount_path.IsParent(chain.back().source_path)) {
291           done[parent] = true;
292           chain.push_back(archives[parent]);
293           parent = 0;  // Search archives[parent]'s parent from the beginning.
294         }
295       }
296
297       // Mount from the tail of chain.
298       for (size_t i = chain.size(); i > 0; --i)
299         DoMountEvent(chromeos::MOUNT_ERROR_NONE, chain[i - 1], kNotRemounting);
300     }
301   }
302
303   disk_mount_manager_->RequestMountInfoRefresh();
304
305   // Subscribe to Profile Preference change.
306   pref_change_registrar_.Init(profile_->GetPrefs());
307   pref_change_registrar_.Add(
308       prefs::kExternalStorageDisabled,
309       base::Bind(&VolumeManager::OnExternalStorageDisabledChanged,
310                  base::Unretained(this)));
311
312   if (CommandLine::ForCurrentProcess()->HasSwitch(
313           switches::kEnablePrivetStorage)) {
314     privet_volume_lister_.reset(new local_discovery::PrivetVolumeLister(
315         base::Bind(&VolumeManager::OnPrivetVolumesAvailable,
316                    base::Unretained(this))));
317     privet_volume_lister_->Start();
318   }
319 }
320
321 void VolumeManager::Shutdown() {
322   pref_change_registrar_.RemoveAll();
323   disk_mount_manager_->RemoveObserver(this);
324
325   if (drive_integration_service_)
326     drive_integration_service_->RemoveObserver(this);
327 }
328
329 void VolumeManager::AddObserver(VolumeManagerObserver* observer) {
330   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
331   DCHECK(observer);
332   observers_.AddObserver(observer);
333 }
334
335 void VolumeManager::RemoveObserver(VolumeManagerObserver* observer) {
336   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
337   DCHECK(observer);
338   observers_.RemoveObserver(observer);
339 }
340
341 std::vector<VolumeInfo> VolumeManager::GetVolumeInfoList() const {
342   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
343
344   std::vector<VolumeInfo> result;
345   for (std::map<std::string, VolumeInfo>::const_iterator iter =
346            mounted_volumes_.begin();
347        iter != mounted_volumes_.end();
348        ++iter) {
349     result.push_back(iter->second);
350   }
351   return result;
352 }
353
354 bool VolumeManager::FindVolumeInfoById(const std::string& volume_id,
355                                        VolumeInfo* result) const {
356   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
357   DCHECK(result);
358
359   std::map<std::string, VolumeInfo>::const_iterator iter =
360       mounted_volumes_.find(volume_id);
361   if (iter == mounted_volumes_.end())
362     return false;
363   *result = iter->second;
364   return true;
365 }
366
367 bool VolumeManager::RegisterDownloadsDirectoryForTesting(
368     const base::FilePath& path) {
369   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
370
371   base::FilePath old_path;
372   if (FindDownloadsMountPointPath(profile_, &old_path)) {
373     DoUnmountEvent(chromeos::MOUNT_ERROR_NONE,
374                    CreateDownloadsVolumeInfo(old_path));
375   }
376
377   bool success = RegisterDownloadsMountPoint(profile_, path);
378   DoMountEvent(
379       success ? chromeos::MOUNT_ERROR_NONE : chromeos::MOUNT_ERROR_INVALID_PATH,
380       CreateDownloadsVolumeInfo(path),
381       false /* is_remounting */);
382   return success;
383 }
384
385 void VolumeManager::OnFileSystemMounted() {
386   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
387
388   // Raise mount event.
389   // We can pass chromeos::MOUNT_ERROR_NONE even when authentication is failed
390   // or network is unreachable. These two errors will be handled later.
391   VolumeInfo volume_info = CreateDriveVolumeInfo(profile_);
392   DoMountEvent(chromeos::MOUNT_ERROR_NONE, volume_info,
393                false /* is_remounting */);
394 }
395
396 void VolumeManager::OnFileSystemBeingUnmounted() {
397   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
398
399   VolumeInfo volume_info = CreateDriveVolumeInfo(profile_);
400   DoUnmountEvent(chromeos::MOUNT_ERROR_NONE, volume_info);
401 }
402
403 void VolumeManager::OnDiskEvent(
404     chromeos::disks::DiskMountManager::DiskEvent event,
405     const chromeos::disks::DiskMountManager::Disk* disk) {
406   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
407
408   // Disregard hidden devices.
409   if (disk->is_hidden())
410     return;
411
412   switch (event) {
413     case chromeos::disks::DiskMountManager::DISK_ADDED: {
414       if (disk->device_path().empty()) {
415         DVLOG(1) << "Empty system path for " << disk->device_path();
416         return;
417       }
418
419       bool mounting = false;
420       if (disk->mount_path().empty() && disk->has_media() &&
421           !profile_->GetPrefs()->GetBoolean(prefs::kExternalStorageDisabled)) {
422         // If disk is not mounted yet and it has media and there is no policy
423         // forbidding external storage, give it a try.
424         // Initiate disk mount operation. MountPath auto-detects the filesystem
425         // format if the second argument is empty. The third argument (mount
426         // label) is not used in a disk mount operation.
427         disk_mount_manager_->MountPath(
428             disk->device_path(), std::string(), std::string(),
429             chromeos::MOUNT_TYPE_DEVICE);
430         mounting = true;
431       }
432
433       // Notify to observers.
434       FOR_EACH_OBSERVER(VolumeManagerObserver, observers_,
435                         OnDiskAdded(*disk, mounting));
436       return;
437     }
438
439     case chromeos::disks::DiskMountManager::DISK_REMOVED:
440       // If the disk is already mounted, unmount it.
441       if (!disk->mount_path().empty()) {
442         disk_mount_manager_->UnmountPath(
443             disk->mount_path(),
444             chromeos::UNMOUNT_OPTIONS_LAZY,
445             chromeos::disks::DiskMountManager::UnmountPathCallback());
446       }
447
448       // Notify to observers.
449       FOR_EACH_OBSERVER(VolumeManagerObserver, observers_,
450                         OnDiskRemoved(*disk));
451       return;
452
453     case chromeos::disks::DiskMountManager::DISK_CHANGED:
454       DVLOG(1) << "Ignore CHANGED event.";
455       return;
456   }
457   NOTREACHED();
458 }
459
460 void VolumeManager::OnDeviceEvent(
461     chromeos::disks::DiskMountManager::DeviceEvent event,
462     const std::string& device_path) {
463   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
464   DVLOG(1) << "OnDeviceEvent: " << event << ", " << device_path;
465
466   switch (event) {
467     case chromeos::disks::DiskMountManager::DEVICE_ADDED:
468       FOR_EACH_OBSERVER(VolumeManagerObserver, observers_,
469                         OnDeviceAdded(device_path));
470       return;
471     case chromeos::disks::DiskMountManager::DEVICE_REMOVED:
472       FOR_EACH_OBSERVER(VolumeManagerObserver, observers_,
473                         OnDeviceRemoved(device_path));
474       return;
475     case chromeos::disks::DiskMountManager::DEVICE_SCANNED:
476       DVLOG(1) << "Ignore SCANNED event: " << device_path;
477       return;
478   }
479   NOTREACHED();
480 }
481
482 void VolumeManager::OnMountEvent(
483     chromeos::disks::DiskMountManager::MountEvent event,
484     chromeos::MountError error_code,
485     const chromeos::disks::DiskMountManager::MountPointInfo& mount_info) {
486   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
487   DCHECK_NE(chromeos::MOUNT_TYPE_INVALID, mount_info.mount_type);
488
489   if (mount_info.mount_type == chromeos::MOUNT_TYPE_ARCHIVE) {
490     // If the file is not mounted now, tell it to drive file system so that
491     // it can handle file caching correctly.
492     // Note that drive file system knows if the file is managed by drive file
493     // system or not, so here we report all paths.
494     if ((event == chromeos::disks::DiskMountManager::MOUNTING &&
495          error_code != chromeos::MOUNT_ERROR_NONE) ||
496         (event == chromeos::disks::DiskMountManager::UNMOUNTING &&
497          error_code == chromeos::MOUNT_ERROR_NONE)) {
498       drive::FileSystemInterface* file_system =
499           drive::util::GetFileSystemByProfile(profile_);
500       if (file_system) {
501         file_system->MarkCacheFileAsUnmounted(
502             base::FilePath(mount_info.source_path),
503             base::Bind(&OnMarkCacheFileAsUnmounted));
504       }
505     }
506   }
507
508   // Notify a mounting/unmounting event to observers.
509   const chromeos::disks::DiskMountManager::Disk* disk =
510       disk_mount_manager_->FindDiskBySourcePath(mount_info.source_path);
511   VolumeInfo volume_info =
512       CreateVolumeInfoFromMountPointInfo(mount_info, disk);
513   switch (event) {
514     case chromeos::disks::DiskMountManager::MOUNTING: {
515       bool is_remounting =
516           disk && mounted_disk_monitor_->DiskIsRemounting(*disk);
517       DoMountEvent(error_code, volume_info, is_remounting);
518       return;
519     }
520     case chromeos::disks::DiskMountManager::UNMOUNTING:
521       DoUnmountEvent(error_code, volume_info);
522       return;
523   }
524   NOTREACHED();
525 }
526
527 void VolumeManager::OnFormatEvent(
528     chromeos::disks::DiskMountManager::FormatEvent event,
529     chromeos::FormatError error_code,
530     const std::string& device_path) {
531   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
532   DVLOG(1) << "OnDeviceEvent: " << event << ", " << error_code
533            << ", " << device_path;
534
535   switch (event) {
536     case chromeos::disks::DiskMountManager::FORMAT_STARTED:
537       FOR_EACH_OBSERVER(
538           VolumeManagerObserver, observers_,
539           OnFormatStarted(device_path,
540                           error_code == chromeos::FORMAT_ERROR_NONE));
541       return;
542     case chromeos::disks::DiskMountManager::FORMAT_COMPLETED:
543       if (error_code == chromeos::FORMAT_ERROR_NONE) {
544         // If format is completed successfully, try to mount the device.
545         // MountPath auto-detects filesystem format if second argument is
546         // empty. The third argument (mount label) is not used in a disk mount
547         // operation.
548         disk_mount_manager_->MountPath(
549             device_path, std::string(), std::string(),
550             chromeos::MOUNT_TYPE_DEVICE);
551       }
552
553       FOR_EACH_OBSERVER(
554           VolumeManagerObserver, observers_,
555           OnFormatCompleted(device_path,
556                             error_code == chromeos::FORMAT_ERROR_NONE));
557
558       return;
559   }
560   NOTREACHED();
561 }
562
563 void VolumeManager::OnExternalStorageDisabledChanged() {
564   // If the policy just got disabled we have to unmount every device currently
565   // mounted. The opposite is fine - we can let the user re-plug her device to
566   // make it available.
567   if (profile_->GetPrefs()->GetBoolean(prefs::kExternalStorageDisabled)) {
568     // We do not iterate on mount_points directly, because mount_points can
569     // be changed by UnmountPath().
570     // TODO(hidehiko): Is it necessary to unmount mounted archives, too, here?
571     while (!disk_mount_manager_->mount_points().empty()) {
572       std::string mount_path =
573           disk_mount_manager_->mount_points().begin()->second.mount_path;
574       disk_mount_manager_->UnmountPath(
575           mount_path,
576           chromeos::UNMOUNT_OPTIONS_NONE,
577           chromeos::disks::DiskMountManager::UnmountPathCallback());
578     }
579   }
580 }
581
582 void VolumeManager::OnPrivetVolumesAvailable(
583     const local_discovery::PrivetVolumeLister::VolumeList& volumes) {
584   for (local_discovery::PrivetVolumeLister::VolumeList::const_iterator i =
585            volumes.begin(); i != volumes.end(); i++) {
586     VolumeInfo volume_info = CreatePrivetVolumeInfo(*i);
587     DoMountEvent(chromeos::MOUNT_ERROR_NONE, volume_info, false);
588   }
589 }
590
591 void VolumeManager::DoMountEvent(chromeos::MountError error_code,
592                                  const VolumeInfo& volume_info,
593                                  bool is_remounting) {
594   // Archive files are mounted globally in system. We however don't want to show
595   // archives from profile-specific folders (Drive/Downloads) of other users in
596   // multi-profile session. To this end, we filter out archives not on the
597   // volumes already mounted on this VolumeManager instance.
598   if (volume_info.type == VOLUME_TYPE_MOUNTED_ARCHIVE_FILE) {
599     // Source may be in Drive cache folder under the current profile directory.
600     bool from_current_profile =
601         profile_->GetPath().IsParent(volume_info.source_path);
602     for (std::map<std::string, VolumeInfo>::const_iterator iter =
603              mounted_volumes_.begin();
604          !from_current_profile && iter != mounted_volumes_.end();
605          ++iter) {
606       if (iter->second.mount_path.IsParent(volume_info.source_path))
607         from_current_profile = true;
608     }
609     if (!from_current_profile)
610       return;
611   }
612
613   if (error_code == chromeos::MOUNT_ERROR_NONE || volume_info.mount_condition)
614     mounted_volumes_[volume_info.volume_id] = volume_info;
615
616   FOR_EACH_OBSERVER(VolumeManagerObserver,
617                     observers_,
618                     OnVolumeMounted(error_code, volume_info, is_remounting));
619 }
620
621 void VolumeManager::DoUnmountEvent(chromeos::MountError error_code,
622                                    const VolumeInfo& volume_info) {
623   if (mounted_volumes_.find(volume_info.volume_id) == mounted_volumes_.end())
624     return;
625   if (error_code == chromeos::MOUNT_ERROR_NONE)
626     mounted_volumes_.erase(volume_info.volume_id);
627
628   FOR_EACH_OBSERVER(VolumeManagerObserver,
629                     observers_,
630                     OnVolumeUnmounted(error_code, volume_info));
631 }
632
633 }  // namespace file_manager