1e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng// Copyright 2014 The Chromium Authors. All rights reserved. 2e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng// Use of this source code is governed by a BSD-style license that can be 3e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng// found in the LICENSE file. 4e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 5e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include "chrome/browser/chromeos/file_system_provider/service.h" 6e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 7e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include "base/files/file_path.h" 8e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include "base/prefs/pref_service.h" 9e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include "base/prefs/scoped_user_pref_update.h" 10e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include "base/stl_util.h" 11e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include "chrome/browser/chromeos/file_system_provider/mount_path_util.h" 12e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include "chrome/browser/chromeos/file_system_provider/observer.h" 13e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include "chrome/browser/chromeos/file_system_provider/provided_file_system.h" 14e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include "chrome/browser/chromeos/file_system_provider/provided_file_system_info.h" 15e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include "chrome/browser/chromeos/file_system_provider/provided_file_system_interface.h" 16e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include "chrome/browser/chromeos/file_system_provider/service_factory.h" 17e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include "chrome/common/pref_names.h" 18e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include "components/pref_registry/pref_registry_syncable.h" 19e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include "extensions/browser/extension_registry.h" 20e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include "extensions/browser/extension_system.h" 21e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include "storage/browser/fileapi/external_mount_points.h" 22e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 23e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengnamespace chromeos { 24e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengnamespace file_system_provider { 25e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengnamespace { 26e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 27e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng// Maximum number of file systems to be mounted in the same time, per profile. 28e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengconst size_t kMaxFileSystems = 16; 29e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 30e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng// Default factory for provided file systems. |profile| must not be NULL. 31e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen ChengProvidedFileSystemInterface* CreateProvidedFileSystem( 32e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng Profile* profile, 33e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng const ProvidedFileSystemInfo& file_system_info) { 34e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng DCHECK(profile); 35e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return new ProvidedFileSystem(profile, file_system_info); 36e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng} 37e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 38e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng} // namespace 39e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 40e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengconst char kPrefKeyFileSystemId[] = "file-system-id"; 41e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengconst char kPrefKeyDisplayName[] = "display-name"; 42e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengconst char kPrefKeyWritable[] = "writable"; 43e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 44e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengvoid RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry) { 45e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng registry->RegisterDictionaryPref( 46e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng prefs::kFileSystemProviderMounted, 47e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); 48e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng} 49e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 50e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen ChengService::Service(Profile* profile, 51e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng extensions::ExtensionRegistry* extension_registry) 52e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng : profile_(profile), 53e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng extension_registry_(extension_registry), 54e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng file_system_factory_(base::Bind(CreateProvidedFileSystem)), 55e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng weak_ptr_factory_(this) { 56e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng extension_registry_->AddObserver(this); 57e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng} 58e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 59e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen ChengService::~Service() { 60e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng extension_registry_->RemoveObserver(this); 61e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 62e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng // Provided file systems should be already unmounted because of receiving 63e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng // OnExtensionUnload calls for each installed extension. However, for tests 64e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng // we may still have mounted extensions. 65e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng // TODO(mtomasz): Create a TestingService class and remove this code. 66e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng ProvidedFileSystemMap::iterator it = file_system_map_.begin(); 67e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng while (it != file_system_map_.end()) { 68e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng const std::string file_system_id = 69e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng it->second->GetFileSystemInfo().file_system_id(); 70e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng const std::string extension_id = 71e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng it->second->GetFileSystemInfo().extension_id(); 72e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng ++it; 73e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng const bool unmount_result = UnmountFileSystem( 74e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng extension_id, file_system_id, UNMOUNT_REASON_SHUTDOWN); 75e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng DCHECK(unmount_result); 76e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng } 77e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 78e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng DCHECK_EQ(0u, file_system_map_.size()); 79e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng STLDeleteValues(&file_system_map_); 80e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng} 81e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 82e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng// static 83e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen ChengService* Service::Get(content::BrowserContext* context) { 84e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return ServiceFactory::Get(context); 85e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng} 86e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 87e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengvoid Service::AddObserver(Observer* observer) { 88e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng DCHECK(observer); 89e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng observers_.AddObserver(observer); 90e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng} 91e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 92e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengvoid Service::RemoveObserver(Observer* observer) { 93e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng DCHECK(observer); 94e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng observers_.RemoveObserver(observer); 95e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng} 96e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 97e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengvoid Service::SetFileSystemFactoryForTesting( 98e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng const FileSystemFactoryCallback& factory_callback) { 99e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng DCHECK(!factory_callback.is_null()); 100e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng file_system_factory_ = factory_callback; 101e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng} 102e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 103e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengbool Service::MountFileSystem(const std::string& extension_id, 104e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng const std::string& file_system_id, 105e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng const std::string& display_name, 106e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng bool writable) { 107e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng DCHECK(thread_checker_.CalledOnValidThread()); 108e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 109e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng // If already exists a file system provided by the same extension with this 110e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng // id, then abort. 111e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (GetProvidedFileSystem(extension_id, file_system_id)) { 112e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng FOR_EACH_OBSERVER(Observer, 113e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng observers_, 114e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng OnProvidedFileSystemMount(ProvidedFileSystemInfo(), 115e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng base::File::FILE_ERROR_EXISTS)); 116e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return false; 117e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng } 118e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 119e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng // Restrict number of file systems to prevent system abusing. 120e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (file_system_map_.size() + 1 > kMaxFileSystems) { 121e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng FOR_EACH_OBSERVER( 122e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng Observer, 123e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng observers_, 124e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng OnProvidedFileSystemMount(ProvidedFileSystemInfo(), 125e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng base::File::FILE_ERROR_TOO_MANY_OPENED)); 126e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return false; 127e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng } 128e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 129e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng storage::ExternalMountPoints* const mount_points = 130e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng storage::ExternalMountPoints::GetSystemInstance(); 131e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng DCHECK(mount_points); 132e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 133e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng // The mount point path and name are unique per system, since they are system 134e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng // wide. This is necessary for copying between profiles. 135e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng const base::FilePath& mount_path = 136e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng util::GetMountPath(profile_, extension_id, file_system_id); 137e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng const std::string mount_point_name = mount_path.BaseName().AsUTF8Unsafe(); 138e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 139e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (!mount_points->RegisterFileSystem(mount_point_name, 140e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng storage::kFileSystemTypeProvided, 141e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng storage::FileSystemMountOption(), 142e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng mount_path)) { 143e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng FOR_EACH_OBSERVER( 144e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng Observer, 145e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng observers_, 146e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng OnProvidedFileSystemMount(ProvidedFileSystemInfo(), 147e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng base::File::FILE_ERROR_INVALID_OPERATION)); 148e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return false; 149e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng } 150e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 151e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng // Store the file system descriptor. Use the mount point name as the file 152e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng // system provider file system id. 153e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng // Examples: 154e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng // file_system_id = hello_world 155e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng // mount_point_name = b33f1337-hello_world-5aa5 156e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng // writable = false 157e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng // mount_path = /provided/b33f1337-hello_world-5aa5 158e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng ProvidedFileSystemInfo file_system_info( 159e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng extension_id, file_system_id, display_name, writable, mount_path); 160e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 161e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng ProvidedFileSystemInterface* file_system = 162e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng file_system_factory_.Run(profile_, file_system_info); 163e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng DCHECK(file_system); 164e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng file_system_map_[FileSystemKey(extension_id, file_system_id)] = file_system; 165e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng mount_point_name_to_key_map_[mount_point_name] = 166e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng FileSystemKey(extension_id, file_system_id); 167e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng RememberFileSystem(file_system_info); 168e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 169e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng FOR_EACH_OBSERVER( 170e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng Observer, 171e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng observers_, 172e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng OnProvidedFileSystemMount(file_system_info, base::File::FILE_OK)); 173e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 174e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return true; 175e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng} 176e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 177e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengbool Service::UnmountFileSystem(const std::string& extension_id, 178e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng const std::string& file_system_id, 179e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng UnmountReason reason) { 180e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng DCHECK(thread_checker_.CalledOnValidThread()); 181e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 182e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng const ProvidedFileSystemMap::iterator file_system_it = 183e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng file_system_map_.find(FileSystemKey(extension_id, file_system_id)); 184e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (file_system_it == file_system_map_.end()) { 185e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng const ProvidedFileSystemInfo empty_file_system_info; 186e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng FOR_EACH_OBSERVER( 187e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng Observer, 188e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng observers_, 189e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng OnProvidedFileSystemUnmount(empty_file_system_info, 190 base::File::FILE_ERROR_NOT_FOUND)); 191 return false; 192 } 193 194 storage::ExternalMountPoints* const mount_points = 195 storage::ExternalMountPoints::GetSystemInstance(); 196 DCHECK(mount_points); 197 198 const ProvidedFileSystemInfo& file_system_info = 199 file_system_it->second->GetFileSystemInfo(); 200 201 const std::string mount_point_name = 202 file_system_info.mount_path().BaseName().value(); 203 if (!mount_points->RevokeFileSystem(mount_point_name)) { 204 FOR_EACH_OBSERVER( 205 Observer, 206 observers_, 207 OnProvidedFileSystemUnmount(file_system_info, 208 base::File::FILE_ERROR_INVALID_OPERATION)); 209 return false; 210 } 211 212 FOR_EACH_OBSERVER( 213 Observer, 214 observers_, 215 OnProvidedFileSystemUnmount(file_system_info, base::File::FILE_OK)); 216 217 mount_point_name_to_key_map_.erase(mount_point_name); 218 219 if (reason == UNMOUNT_REASON_USER) { 220 ForgetFileSystem(file_system_info.extension_id(), 221 file_system_info.file_system_id()); 222 } 223 224 delete file_system_it->second; 225 file_system_map_.erase(file_system_it); 226 227 return true; 228} 229 230bool Service::RequestUnmount(const std::string& extension_id, 231 const std::string& file_system_id) { 232 DCHECK(thread_checker_.CalledOnValidThread()); 233 234 ProvidedFileSystemMap::iterator file_system_it = 235 file_system_map_.find(FileSystemKey(extension_id, file_system_id)); 236 if (file_system_it == file_system_map_.end()) 237 return false; 238 239 file_system_it->second->RequestUnmount( 240 base::Bind(&Service::OnRequestUnmountStatus, 241 weak_ptr_factory_.GetWeakPtr(), 242 file_system_it->second->GetFileSystemInfo())); 243 return true; 244} 245 246std::vector<ProvidedFileSystemInfo> Service::GetProvidedFileSystemInfoList() { 247 DCHECK(thread_checker_.CalledOnValidThread()); 248 249 std::vector<ProvidedFileSystemInfo> result; 250 for (ProvidedFileSystemMap::const_iterator it = file_system_map_.begin(); 251 it != file_system_map_.end(); 252 ++it) { 253 result.push_back(it->second->GetFileSystemInfo()); 254 } 255 return result; 256} 257 258ProvidedFileSystemInterface* Service::GetProvidedFileSystem( 259 const std::string& extension_id, 260 const std::string& file_system_id) { 261 DCHECK(thread_checker_.CalledOnValidThread()); 262 263 const ProvidedFileSystemMap::const_iterator file_system_it = 264 file_system_map_.find(FileSystemKey(extension_id, file_system_id)); 265 if (file_system_it == file_system_map_.end()) 266 return NULL; 267 268 return file_system_it->second; 269} 270 271void Service::OnExtensionUnloaded( 272 content::BrowserContext* browser_context, 273 const extensions::Extension* extension, 274 extensions::UnloadedExtensionInfo::Reason reason) { 275 // Unmount all of the provided file systems associated with this extension. 276 ProvidedFileSystemMap::iterator it = file_system_map_.begin(); 277 while (it != file_system_map_.end()) { 278 const ProvidedFileSystemInfo& file_system_info = 279 it->second->GetFileSystemInfo(); 280 // Advance the iterator beforehand, otherwise it will become invalidated 281 // by the UnmountFileSystem() call. 282 ++it; 283 if (file_system_info.extension_id() == extension->id()) { 284 const bool unmount_result = UnmountFileSystem( 285 file_system_info.extension_id(), 286 file_system_info.file_system_id(), 287 reason == extensions::UnloadedExtensionInfo::REASON_PROFILE_SHUTDOWN 288 ? UNMOUNT_REASON_SHUTDOWN 289 : UNMOUNT_REASON_USER); 290 DCHECK(unmount_result); 291 } 292 } 293} 294 295void Service::OnExtensionLoaded(content::BrowserContext* browser_context, 296 const extensions::Extension* extension) { 297 RestoreFileSystems(extension->id()); 298} 299 300ProvidedFileSystemInterface* Service::GetProvidedFileSystem( 301 const std::string& mount_point_name) { 302 DCHECK(thread_checker_.CalledOnValidThread()); 303 304 const MountPointNameToKeyMap::const_iterator mapping_it = 305 mount_point_name_to_key_map_.find(mount_point_name); 306 if (mapping_it == mount_point_name_to_key_map_.end()) 307 return NULL; 308 309 const ProvidedFileSystemMap::const_iterator file_system_it = 310 file_system_map_.find(mapping_it->second); 311 if (file_system_it == file_system_map_.end()) 312 return NULL; 313 314 return file_system_it->second; 315} 316 317void Service::OnRequestUnmountStatus( 318 const ProvidedFileSystemInfo& file_system_info, 319 base::File::Error error) { 320 // Notify observers about failure in unmounting, since mount() will not be 321 // called by the provided file system. In case of success mount() will be 322 // invoked, and observers notified, so there is no need to call them now. 323 if (error != base::File::FILE_OK) { 324 FOR_EACH_OBSERVER(Observer, 325 observers_, 326 OnProvidedFileSystemUnmount(file_system_info, error)); 327 } 328} 329 330void Service::RememberFileSystem( 331 const ProvidedFileSystemInfo& file_system_info) { 332 base::DictionaryValue* file_system = new base::DictionaryValue(); 333 file_system->SetStringWithoutPathExpansion(kPrefKeyFileSystemId, 334 file_system_info.file_system_id()); 335 file_system->SetStringWithoutPathExpansion(kPrefKeyDisplayName, 336 file_system_info.display_name()); 337 file_system->SetBooleanWithoutPathExpansion(kPrefKeyWritable, 338 file_system_info.writable()); 339 340 PrefService* const pref_service = profile_->GetPrefs(); 341 DCHECK(pref_service); 342 343 DictionaryPrefUpdate dict_update(pref_service, 344 prefs::kFileSystemProviderMounted); 345 346 base::DictionaryValue* file_systems_per_extension = NULL; 347 if (!dict_update->GetDictionaryWithoutPathExpansion( 348 file_system_info.extension_id(), &file_systems_per_extension)) { 349 file_systems_per_extension = new base::DictionaryValue(); 350 dict_update->SetWithoutPathExpansion(file_system_info.extension_id(), 351 file_systems_per_extension); 352 } 353 354 file_systems_per_extension->SetWithoutPathExpansion( 355 file_system_info.file_system_id(), file_system); 356} 357 358void Service::ForgetFileSystem(const std::string& extension_id, 359 const std::string& file_system_id) { 360 PrefService* const pref_service = profile_->GetPrefs(); 361 DCHECK(pref_service); 362 363 DictionaryPrefUpdate dict_update(pref_service, 364 prefs::kFileSystemProviderMounted); 365 366 base::DictionaryValue* file_systems_per_extension = NULL; 367 if (!dict_update->GetDictionaryWithoutPathExpansion( 368 extension_id, &file_systems_per_extension)) 369 return; // Nothing to forget. 370 371 file_systems_per_extension->RemoveWithoutPathExpansion(file_system_id, NULL); 372 if (!file_systems_per_extension->size()) 373 dict_update->Remove(extension_id, NULL); 374} 375 376void Service::RestoreFileSystems(const std::string& extension_id) { 377 PrefService* const pref_service = profile_->GetPrefs(); 378 DCHECK(pref_service); 379 380 const base::DictionaryValue* const file_systems = 381 pref_service->GetDictionary(prefs::kFileSystemProviderMounted); 382 DCHECK(file_systems); 383 384 const base::DictionaryValue* file_systems_per_extension = NULL; 385 if (!file_systems->GetDictionaryWithoutPathExpansion( 386 extension_id, &file_systems_per_extension)) 387 return; // Nothing to restore. 388 389 // Use a copy of the dictionary, since the original one may be modified while 390 // iterating over it. 391 scoped_ptr<const base::DictionaryValue> file_systems_per_extension_copy( 392 file_systems_per_extension->DeepCopy()); 393 394 for (base::DictionaryValue::Iterator it(*file_systems_per_extension_copy); 395 !it.IsAtEnd(); 396 it.Advance()) { 397 const base::Value* file_system_value = NULL; 398 const base::DictionaryValue* file_system = NULL; 399 file_systems_per_extension_copy->GetWithoutPathExpansion( 400 it.key(), &file_system_value); 401 DCHECK(file_system_value); 402 403 std::string file_system_id; 404 std::string display_name; 405 bool writable; 406 407 if (!file_system_value->GetAsDictionary(&file_system) || 408 !file_system->GetStringWithoutPathExpansion(kPrefKeyFileSystemId, 409 &file_system_id) || 410 !file_system->GetStringWithoutPathExpansion(kPrefKeyDisplayName, 411 &display_name) || 412 !file_system->GetBooleanWithoutPathExpansion(kPrefKeyWritable, 413 &writable) || 414 file_system_id.empty() || display_name.empty()) { 415 LOG(ERROR) 416 << "Malformed provided file system information in preferences."; 417 continue; 418 } 419 420 const bool result = 421 MountFileSystem(extension_id, file_system_id, display_name, writable); 422 if (!result) { 423 LOG(ERROR) << "Failed to restore a provided file system from " 424 << "preferences: " << extension_id << ", " << file_system_id 425 << ", " << display_name << "."; 426 // Since remounting of the file system failed, then remove it from 427 // preferences to avoid remounting it over and over again with a failure. 428 ForgetFileSystem(extension_id, file_system_id); 429 } 430 } 431} 432 433} // namespace file_system_provider 434} // namespace chromeos 435