service.cc revision 116680a4aac90f2aa7413d9095a592090648e557
1f540c54701e3eeb34cb619a3a4eb18f1ac70ef2dJordan Rose// Copyright 2014 The Chromium Authors. All rights reserved. 2740d490593e0de8732a697c9f77b90ddd463863bJordan Rose// Use of this source code is governed by a BSD-style license that can be 3740d490593e0de8732a697c9f77b90ddd463863bJordan Rose// found in the LICENSE file. 4740d490593e0de8732a697c9f77b90ddd463863bJordan Rose 5740d490593e0de8732a697c9f77b90ddd463863bJordan Rose#include "chrome/browser/chromeos/file_system_provider/service.h" 6740d490593e0de8732a697c9f77b90ddd463863bJordan Rose 7740d490593e0de8732a697c9f77b90ddd463863bJordan Rose#include "base/files/file_path.h" 8740d490593e0de8732a697c9f77b90ddd463863bJordan Rose#include "base/prefs/pref_service.h" 9740d490593e0de8732a697c9f77b90ddd463863bJordan Rose#include "base/prefs/scoped_user_pref_update.h" 10740d490593e0de8732a697c9f77b90ddd463863bJordan Rose#include "base/stl_util.h" 11740d490593e0de8732a697c9f77b90ddd463863bJordan Rose#include "chrome/browser/chromeos/file_system_provider/mount_path_util.h" 12740d490593e0de8732a697c9f77b90ddd463863bJordan Rose#include "chrome/browser/chromeos/file_system_provider/observer.h" 13740d490593e0de8732a697c9f77b90ddd463863bJordan Rose#include "chrome/browser/chromeos/file_system_provider/provided_file_system.h" 14740d490593e0de8732a697c9f77b90ddd463863bJordan Rose#include "chrome/browser/chromeos/file_system_provider/provided_file_system_info.h" 15740d490593e0de8732a697c9f77b90ddd463863bJordan Rose#include "chrome/browser/chromeos/file_system_provider/provided_file_system_interface.h" 16740d490593e0de8732a697c9f77b90ddd463863bJordan Rose#include "chrome/browser/chromeos/file_system_provider/service_factory.h" 17740d490593e0de8732a697c9f77b90ddd463863bJordan Rose#include "chrome/common/pref_names.h" 18740d490593e0de8732a697c9f77b90ddd463863bJordan Rose#include "components/pref_registry/pref_registry_syncable.h" 19740d490593e0de8732a697c9f77b90ddd463863bJordan Rose#include "extensions/browser/extension_registry.h" 20740d490593e0de8732a697c9f77b90ddd463863bJordan Rose#include "extensions/browser/extension_system.h" 21740d490593e0de8732a697c9f77b90ddd463863bJordan Rose#include "webkit/browser/fileapi/external_mount_points.h" 22a43df9539644bf1c258e12710cd69d79b0b078cdTed Kremenek 2330a2e16f6c27f888dd11eba6bbbae1e980078fcbChandler Carruthnamespace chromeos { 24de507eaf3cb54d3cb234dc14499c10ab3373d15fJordan Rosenamespace file_system_provider { 25740d490593e0de8732a697c9f77b90ddd463863bJordan Rosenamespace { 26b7a23e05d1d8f07f2a6edce5c88c728fe894c2c7Jordan Rose 27740d490593e0de8732a697c9f77b90ddd463863bJordan Rose// Maximum number of file systems to be mounted in the same time, per profile. 28740d490593e0de8732a697c9f77b90ddd463863bJordan Roseconst size_t kMaxFileSystems = 16; 2928038f33aa2db4833881fea757a1f0daf85ac02bJordan Rose 3028038f33aa2db4833881fea757a1f0daf85ac02bJordan Rose// Default factory for provided file systems. |profile| must not be NULL. 3128038f33aa2db4833881fea757a1f0daf85ac02bJordan RoseProvidedFileSystemInterface* CreateProvidedFileSystem( 32740d490593e0de8732a697c9f77b90ddd463863bJordan Rose Profile* profile, 33740d490593e0de8732a697c9f77b90ddd463863bJordan Rose const ProvidedFileSystemInfo& file_system_info) { 34740d490593e0de8732a697c9f77b90ddd463863bJordan Rose DCHECK(profile); 35740d490593e0de8732a697c9f77b90ddd463863bJordan Rose return new ProvidedFileSystem(profile, file_system_info); 36740d490593e0de8732a697c9f77b90ddd463863bJordan Rose} 37740d490593e0de8732a697c9f77b90ddd463863bJordan Rose 38740d490593e0de8732a697c9f77b90ddd463863bJordan Rose} // namespace 39645baeed6800f952e9ad1d5666e01080385531a2Jordan Rose 40645baeed6800f952e9ad1d5666e01080385531a2Jordan Roseconst char kPrefKeyFileSystemId[] = "file-system-id"; 418d276d38c258dfc572586daf6c0e8f8fce249c0eJordan Roseconst char kPrefKeyDisplayName[] = "display-name"; 42645baeed6800f952e9ad1d5666e01080385531a2Jordan Roseconst char kPrefKeyWritable[] = "writable"; 43645baeed6800f952e9ad1d5666e01080385531a2Jordan Rose 44645baeed6800f952e9ad1d5666e01080385531a2Jordan Rosevoid RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry) { 4570cbf3cc09eb21db1108396d30a414ea66d842ccJordan Rose registry->RegisterDictionaryPref( 46740d490593e0de8732a697c9f77b90ddd463863bJordan Rose prefs::kFileSystemProviderMounted, 4770cbf3cc09eb21db1108396d30a414ea66d842ccJordan Rose user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); 488919e688dc610d1f632a4d43f7f1489f67255476Jordan Rose} 49740d490593e0de8732a697c9f77b90ddd463863bJordan Rose 50740d490593e0de8732a697c9f77b90ddd463863bJordan RoseService::Service(Profile* profile, 51972a3680bdd95f2e9d6316b391f1c47513dc78ccJordan Rose extensions::ExtensionRegistry* extension_registry) 52d563d3fb73879df7147b8a5302c3bf0e1402ba18Jordan Rose : profile_(profile), 53972a3680bdd95f2e9d6316b391f1c47513dc78ccJordan Rose extension_registry_(extension_registry), 54d563d3fb73879df7147b8a5302c3bf0e1402ba18Jordan Rose file_system_factory_(base::Bind(CreateProvidedFileSystem)), 55d563d3fb73879df7147b8a5302c3bf0e1402ba18Jordan Rose weak_ptr_factory_(this) { 56d563d3fb73879df7147b8a5302c3bf0e1402ba18Jordan Rose extension_registry_->AddObserver(this); 57d563d3fb73879df7147b8a5302c3bf0e1402ba18Jordan Rose} 58d563d3fb73879df7147b8a5302c3bf0e1402ba18Jordan Rose 59d563d3fb73879df7147b8a5302c3bf0e1402ba18Jordan RoseService::~Service() { 60d563d3fb73879df7147b8a5302c3bf0e1402ba18Jordan Rose extension_registry_->RemoveObserver(this); 61d563d3fb73879df7147b8a5302c3bf0e1402ba18Jordan Rose 62d563d3fb73879df7147b8a5302c3bf0e1402ba18Jordan Rose // Provided file systems should be already unmounted because of receiving 6357c033621dacd8720ac9ff65a09025f14f70e22fJordan Rose // OnExtensionUnload calls for each installed extension. However, for tests 6457c033621dacd8720ac9ff65a09025f14f70e22fJordan Rose // we may still have mounted extensions. 6557c033621dacd8720ac9ff65a09025f14f70e22fJordan Rose // TODO(mtomasz): Create a TestingService class and remove this code. 6657c033621dacd8720ac9ff65a09025f14f70e22fJordan Rose ProvidedFileSystemMap::iterator it = file_system_map_.begin(); 6757c033621dacd8720ac9ff65a09025f14f70e22fJordan Rose while (it != file_system_map_.end()) { 6857c033621dacd8720ac9ff65a09025f14f70e22fJordan Rose const std::string file_system_id = 6957c033621dacd8720ac9ff65a09025f14f70e22fJordan Rose it->second->GetFileSystemInfo().file_system_id(); 70d563d3fb73879df7147b8a5302c3bf0e1402ba18Jordan Rose const std::string extension_id = 71b7a23e05d1d8f07f2a6edce5c88c728fe894c2c7Jordan Rose it->second->GetFileSystemInfo().extension_id(); 721becab2120142b1be87d684a68d3bea98f5abfb5Anna Zaks ++it; 735960f4aeac9760198c80e05d70d8dadb1db0ff0eAnna Zaks const bool unmount_result = UnmountFileSystem( 741becab2120142b1be87d684a68d3bea98f5abfb5Anna Zaks extension_id, file_system_id, UNMOUNT_REASON_SHUTDOWN); 751becab2120142b1be87d684a68d3bea98f5abfb5Anna Zaks DCHECK(unmount_result); 761becab2120142b1be87d684a68d3bea98f5abfb5Anna Zaks } 771becab2120142b1be87d684a68d3bea98f5abfb5Anna Zaks 781becab2120142b1be87d684a68d3bea98f5abfb5Anna Zaks DCHECK_EQ(0u, file_system_map_.size()); 79fc05decf08feefd2ffe8cc250219aee6eab3119cAnna Zaks STLDeleteValues(&file_system_map_); 801becab2120142b1be87d684a68d3bea98f5abfb5Anna Zaks} 811becab2120142b1be87d684a68d3bea98f5abfb5Anna Zaks 82fc05decf08feefd2ffe8cc250219aee6eab3119cAnna Zaks// static 835960f4aeac9760198c80e05d70d8dadb1db0ff0eAnna ZaksService* Service::Get(content::BrowserContext* context) { 845960f4aeac9760198c80e05d70d8dadb1db0ff0eAnna Zaks return ServiceFactory::Get(context); 855960f4aeac9760198c80e05d70d8dadb1db0ff0eAnna Zaks} 861becab2120142b1be87d684a68d3bea98f5abfb5Anna Zaks 871becab2120142b1be87d684a68d3bea98f5abfb5Anna Zaksvoid Service::AddObserver(Observer* observer) { 88fc05decf08feefd2ffe8cc250219aee6eab3119cAnna Zaks DCHECK(observer); 895960f4aeac9760198c80e05d70d8dadb1db0ff0eAnna Zaks observers_.AddObserver(observer); 90fc05decf08feefd2ffe8cc250219aee6eab3119cAnna Zaks} 91fc05decf08feefd2ffe8cc250219aee6eab3119cAnna Zaks 92fc05decf08feefd2ffe8cc250219aee6eab3119cAnna Zaksvoid Service::RemoveObserver(Observer* observer) { 93fc05decf08feefd2ffe8cc250219aee6eab3119cAnna Zaks DCHECK(observer); 945960f4aeac9760198c80e05d70d8dadb1db0ff0eAnna Zaks observers_.RemoveObserver(observer); 951becab2120142b1be87d684a68d3bea98f5abfb5Anna Zaks} 961becab2120142b1be87d684a68d3bea98f5abfb5Anna Zaks 971becab2120142b1be87d684a68d3bea98f5abfb5Anna Zaksvoid Service::SetFileSystemFactoryForTesting( 981becab2120142b1be87d684a68d3bea98f5abfb5Anna Zaks const FileSystemFactoryCallback& factory_callback) { 995960f4aeac9760198c80e05d70d8dadb1db0ff0eAnna Zaks DCHECK(!factory_callback.is_null()); 1001becab2120142b1be87d684a68d3bea98f5abfb5Anna Zaks file_system_factory_ = factory_callback; 1011becab2120142b1be87d684a68d3bea98f5abfb5Anna Zaks} 1021becab2120142b1be87d684a68d3bea98f5abfb5Anna Zaks 1031becab2120142b1be87d684a68d3bea98f5abfb5Anna Zaksbool Service::MountFileSystem(const std::string& extension_id, 104e90d3f847dcce76237078b67db8895eb7a24189eAnna Zaks const std::string& file_system_id, 105e90d3f847dcce76237078b67db8895eb7a24189eAnna Zaks const std::string& display_name, 106740d490593e0de8732a697c9f77b90ddd463863bJordan Rose bool writable) { 107740d490593e0de8732a697c9f77b90ddd463863bJordan Rose DCHECK(thread_checker_.CalledOnValidThread()); 108972a3680bdd95f2e9d6316b391f1c47513dc78ccJordan Rose 109972a3680bdd95f2e9d6316b391f1c47513dc78ccJordan Rose // If already exists a file system provided by the same extension with this 110972a3680bdd95f2e9d6316b391f1c47513dc78ccJordan Rose // id, then abort. 111972a3680bdd95f2e9d6316b391f1c47513dc78ccJordan Rose if (GetProvidedFileSystem(extension_id, file_system_id)) { 112972a3680bdd95f2e9d6316b391f1c47513dc78ccJordan Rose FOR_EACH_OBSERVER(Observer, 113972a3680bdd95f2e9d6316b391f1c47513dc78ccJordan Rose observers_, 114972a3680bdd95f2e9d6316b391f1c47513dc78ccJordan Rose OnProvidedFileSystemMount(ProvidedFileSystemInfo(), 115740d490593e0de8732a697c9f77b90ddd463863bJordan Rose base::File::FILE_ERROR_EXISTS)); 116740d490593e0de8732a697c9f77b90ddd463863bJordan Rose return false; 117740d490593e0de8732a697c9f77b90ddd463863bJordan Rose } 118740d490593e0de8732a697c9f77b90ddd463863bJordan Rose 119b7a23e05d1d8f07f2a6edce5c88c728fe894c2c7Jordan Rose // Restrict number of file systems to prevent system abusing. 1207c99aa385178c630e29f671299cdd9c104f1c885Jordan Rose if (file_system_map_.size() + 1 > kMaxFileSystems) { 1217c99aa385178c630e29f671299cdd9c104f1c885Jordan Rose FOR_EACH_OBSERVER( 122b7a23e05d1d8f07f2a6edce5c88c728fe894c2c7Jordan Rose Observer, 123b7a23e05d1d8f07f2a6edce5c88c728fe894c2c7Jordan Rose observers_, 124f56faa01936b9cf909623d7f06e3c2569ca4a78eDmitri Gribenko OnProvidedFileSystemMount(ProvidedFileSystemInfo(), 1257c99aa385178c630e29f671299cdd9c104f1c885Jordan Rose base::File::FILE_ERROR_TOO_MANY_OPENED)); 126740d490593e0de8732a697c9f77b90ddd463863bJordan Rose return false; 127b7a23e05d1d8f07f2a6edce5c88c728fe894c2c7Jordan Rose } 128b7a23e05d1d8f07f2a6edce5c88c728fe894c2c7Jordan Rose 129972a3680bdd95f2e9d6316b391f1c47513dc78ccJordan Rose fileapi::ExternalMountPoints* const mount_points = 130972a3680bdd95f2e9d6316b391f1c47513dc78ccJordan Rose fileapi::ExternalMountPoints::GetSystemInstance(); 131972a3680bdd95f2e9d6316b391f1c47513dc78ccJordan Rose DCHECK(mount_points); 132972a3680bdd95f2e9d6316b391f1c47513dc78ccJordan Rose 133b7a23e05d1d8f07f2a6edce5c88c728fe894c2c7Jordan Rose // The mount point path and name are unique per system, since they are system 134b7a23e05d1d8f07f2a6edce5c88c728fe894c2c7Jordan Rose // wide. This is necessary for copying between profiles. 135972a3680bdd95f2e9d6316b391f1c47513dc78ccJordan Rose const base::FilePath& mount_path = 136972a3680bdd95f2e9d6316b391f1c47513dc78ccJordan Rose util::GetMountPath(profile_, extension_id, file_system_id); 137972a3680bdd95f2e9d6316b391f1c47513dc78ccJordan Rose const std::string mount_point_name = mount_path.BaseName().AsUTF8Unsafe(); 138972a3680bdd95f2e9d6316b391f1c47513dc78ccJordan Rose 139972a3680bdd95f2e9d6316b391f1c47513dc78ccJordan Rose if (!mount_points->RegisterFileSystem(mount_point_name, 140972a3680bdd95f2e9d6316b391f1c47513dc78ccJordan Rose fileapi::kFileSystemTypeProvided, 141972a3680bdd95f2e9d6316b391f1c47513dc78ccJordan Rose fileapi::FileSystemMountOption(), 142972a3680bdd95f2e9d6316b391f1c47513dc78ccJordan Rose mount_path)) { 143d563d3fb73879df7147b8a5302c3bf0e1402ba18Jordan Rose FOR_EACH_OBSERVER( 144d563d3fb73879df7147b8a5302c3bf0e1402ba18Jordan Rose Observer, 1455204d9e2fe0ea4e4b9c85087e355021c93221764Jordan Rose observers_, 146972a3680bdd95f2e9d6316b391f1c47513dc78ccJordan Rose OnProvidedFileSystemMount(ProvidedFileSystemInfo(), 147b7a23e05d1d8f07f2a6edce5c88c728fe894c2c7Jordan Rose base::File::FILE_ERROR_INVALID_OPERATION)); 1485204d9e2fe0ea4e4b9c85087e355021c93221764Jordan Rose return false; 149972a3680bdd95f2e9d6316b391f1c47513dc78ccJordan Rose } 150972a3680bdd95f2e9d6316b391f1c47513dc78ccJordan Rose 151972a3680bdd95f2e9d6316b391f1c47513dc78ccJordan Rose // Store the file system descriptor. Use the mount point name as the file 152972a3680bdd95f2e9d6316b391f1c47513dc78ccJordan Rose // system provider file system id. 153972a3680bdd95f2e9d6316b391f1c47513dc78ccJordan Rose // Examples: 154972a3680bdd95f2e9d6316b391f1c47513dc78ccJordan Rose // file_system_id = hello_world 155b7a23e05d1d8f07f2a6edce5c88c728fe894c2c7Jordan Rose // mount_point_name = b33f1337-hello_world-5aa5 156972a3680bdd95f2e9d6316b391f1c47513dc78ccJordan Rose // writable = false 157972a3680bdd95f2e9d6316b391f1c47513dc78ccJordan Rose // mount_path = /provided/b33f1337-hello_world-5aa5 158972a3680bdd95f2e9d6316b391f1c47513dc78ccJordan Rose ProvidedFileSystemInfo file_system_info( 159740d490593e0de8732a697c9f77b90ddd463863bJordan Rose extension_id, file_system_id, display_name, writable, mount_path); 160740d490593e0de8732a697c9f77b90ddd463863bJordan Rose 161b7a23e05d1d8f07f2a6edce5c88c728fe894c2c7Jordan Rose ProvidedFileSystemInterface* file_system = 162740d490593e0de8732a697c9f77b90ddd463863bJordan Rose file_system_factory_.Run(profile_, file_system_info); 163740d490593e0de8732a697c9f77b90ddd463863bJordan Rose DCHECK(file_system); 164972a3680bdd95f2e9d6316b391f1c47513dc78ccJordan Rose file_system_map_[FileSystemKey(extension_id, file_system_id)] = file_system; 165740d490593e0de8732a697c9f77b90ddd463863bJordan Rose mount_point_name_to_key_map_[mount_point_name] = 166740d490593e0de8732a697c9f77b90ddd463863bJordan Rose FileSystemKey(extension_id, file_system_id); 167740d490593e0de8732a697c9f77b90ddd463863bJordan Rose RememberFileSystem(file_system_info); 168740d490593e0de8732a697c9f77b90ddd463863bJordan Rose 1697c99aa385178c630e29f671299cdd9c104f1c885Jordan Rose FOR_EACH_OBSERVER( 170740d490593e0de8732a697c9f77b90ddd463863bJordan Rose Observer, 171740d490593e0de8732a697c9f77b90ddd463863bJordan Rose observers_, 1727c99aa385178c630e29f671299cdd9c104f1c885Jordan Rose OnProvidedFileSystemMount(file_system_info, base::File::FILE_OK)); 1737c99aa385178c630e29f671299cdd9c104f1c885Jordan Rose 174b7a23e05d1d8f07f2a6edce5c88c728fe894c2c7Jordan Rose return true; 1757c99aa385178c630e29f671299cdd9c104f1c885Jordan Rose} 176b7a23e05d1d8f07f2a6edce5c88c728fe894c2c7Jordan Rose 177740d490593e0de8732a697c9f77b90ddd463863bJordan Rosebool Service::UnmountFileSystem(const std::string& extension_id, 178740d490593e0de8732a697c9f77b90ddd463863bJordan Rose const std::string& file_system_id, 1797c99aa385178c630e29f671299cdd9c104f1c885Jordan Rose UnmountReason reason) { 1807c99aa385178c630e29f671299cdd9c104f1c885Jordan Rose DCHECK(thread_checker_.CalledOnValidThread()); 1817c99aa385178c630e29f671299cdd9c104f1c885Jordan Rose 182740d490593e0de8732a697c9f77b90ddd463863bJordan Rose const ProvidedFileSystemMap::iterator file_system_it = 1835a90193ad825656d4a03099cd5e9c928d1782b5eAnna Zaks file_system_map_.find(FileSystemKey(extension_id, file_system_id)); 1840a6e09f67c719c318856be19d57e19972101f62cJordan Rose if (file_system_it == file_system_map_.end()) { 1855a90193ad825656d4a03099cd5e9c928d1782b5eAnna Zaks const ProvidedFileSystemInfo empty_file_system_info; 1865a90193ad825656d4a03099cd5e9c928d1782b5eAnna Zaks FOR_EACH_OBSERVER( 1875a90193ad825656d4a03099cd5e9c928d1782b5eAnna Zaks Observer, 1885a90193ad825656d4a03099cd5e9c928d1782b5eAnna Zaks observers_, 1895a90193ad825656d4a03099cd5e9c928d1782b5eAnna Zaks OnProvidedFileSystemUnmount(empty_file_system_info, 1905a90193ad825656d4a03099cd5e9c928d1782b5eAnna Zaks base::File::FILE_ERROR_NOT_FOUND)); 1915a90193ad825656d4a03099cd5e9c928d1782b5eAnna Zaks return false; 1925a90193ad825656d4a03099cd5e9c928d1782b5eAnna Zaks } 193ee158bc29bc12ce544996f7cdfde14aba63acf4dJordan Rose 1945960f4aeac9760198c80e05d70d8dadb1db0ff0eAnna Zaks fileapi::ExternalMountPoints* const mount_points = 195ddc0c4814788dda4ef224cd4d22d07154a6ede49Ted Kremenek fileapi::ExternalMountPoints::GetSystemInstance(); 196ee158bc29bc12ce544996f7cdfde14aba63acf4dJordan Rose DCHECK(mount_points); 197740d490593e0de8732a697c9f77b90ddd463863bJordan Rose 198740d490593e0de8732a697c9f77b90ddd463863bJordan Rose const ProvidedFileSystemInfo& file_system_info = 199b7a23e05d1d8f07f2a6edce5c88c728fe894c2c7Jordan Rose file_system_it->second->GetFileSystemInfo(); 200b7a23e05d1d8f07f2a6edce5c88c728fe894c2c7Jordan Rose 201b7a23e05d1d8f07f2a6edce5c88c728fe894c2c7Jordan Rose const std::string mount_point_name = 202740d490593e0de8732a697c9f77b90ddd463863bJordan Rose file_system_info.mount_path().BaseName().value(); 203740d490593e0de8732a697c9f77b90ddd463863bJordan Rose if (!mount_points->RevokeFileSystem(mount_point_name)) { 204740d490593e0de8732a697c9f77b90ddd463863bJordan Rose FOR_EACH_OBSERVER( 205740d490593e0de8732a697c9f77b90ddd463863bJordan Rose Observer, 206740d490593e0de8732a697c9f77b90ddd463863bJordan Rose observers_, 207740d490593e0de8732a697c9f77b90ddd463863bJordan Rose OnProvidedFileSystemUnmount(file_system_info, 2087c99aa385178c630e29f671299cdd9c104f1c885Jordan Rose base::File::FILE_ERROR_INVALID_OPERATION)); 209740d490593e0de8732a697c9f77b90ddd463863bJordan Rose return false; 210740d490593e0de8732a697c9f77b90ddd463863bJordan Rose } 211740d490593e0de8732a697c9f77b90ddd463863bJordan Rose 212740d490593e0de8732a697c9f77b90ddd463863bJordan Rose FOR_EACH_OBSERVER( 213740d490593e0de8732a697c9f77b90ddd463863bJordan Rose Observer, 214740d490593e0de8732a697c9f77b90ddd463863bJordan Rose observers_, 215740d490593e0de8732a697c9f77b90ddd463863bJordan Rose OnProvidedFileSystemUnmount(file_system_info, base::File::FILE_OK)); 216740d490593e0de8732a697c9f77b90ddd463863bJordan Rose 217740d490593e0de8732a697c9f77b90ddd463863bJordan Rose mount_point_name_to_key_map_.erase(mount_point_name); 218740d490593e0de8732a697c9f77b90ddd463863bJordan Rose 219b7a23e05d1d8f07f2a6edce5c88c728fe894c2c7Jordan Rose if (reason == UNMOUNT_REASON_USER) { 220740d490593e0de8732a697c9f77b90ddd463863bJordan Rose ForgetFileSystem(file_system_info.extension_id(), 221740d490593e0de8732a697c9f77b90ddd463863bJordan Rose file_system_info.file_system_id()); 222740d490593e0de8732a697c9f77b90ddd463863bJordan Rose } 223740d490593e0de8732a697c9f77b90ddd463863bJordan Rose 224740d490593e0de8732a697c9f77b90ddd463863bJordan Rose delete file_system_it->second; 225740d490593e0de8732a697c9f77b90ddd463863bJordan Rose file_system_map_.erase(file_system_it); 226740d490593e0de8732a697c9f77b90ddd463863bJordan Rose 227740d490593e0de8732a697c9f77b90ddd463863bJordan Rose return true; 228740d490593e0de8732a697c9f77b90ddd463863bJordan Rose} 229740d490593e0de8732a697c9f77b90ddd463863bJordan Rose 230740d490593e0de8732a697c9f77b90ddd463863bJordan Rosebool Service::RequestUnmount(const std::string& extension_id, 231de507eaf3cb54d3cb234dc14499c10ab3373d15fJordan Rose const std::string& file_system_id) { 232de507eaf3cb54d3cb234dc14499c10ab3373d15fJordan Rose DCHECK(thread_checker_.CalledOnValidThread()); 2337c99aa385178c630e29f671299cdd9c104f1c885Jordan Rose 2347c99aa385178c630e29f671299cdd9c104f1c885Jordan Rose ProvidedFileSystemMap::iterator file_system_it = 2357c99aa385178c630e29f671299cdd9c104f1c885Jordan Rose file_system_map_.find(FileSystemKey(extension_id, file_system_id)); 236de507eaf3cb54d3cb234dc14499c10ab3373d15fJordan Rose if (file_system_it == file_system_map_.end()) 237740d490593e0de8732a697c9f77b90ddd463863bJordan Rose return false; 2387c99aa385178c630e29f671299cdd9c104f1c885Jordan Rose 239740d490593e0de8732a697c9f77b90ddd463863bJordan Rose file_system_it->second->RequestUnmount( 240740d490593e0de8732a697c9f77b90ddd463863bJordan Rose base::Bind(&Service::OnRequestUnmountStatus, 241740d490593e0de8732a697c9f77b90ddd463863bJordan Rose weak_ptr_factory_.GetWeakPtr(), 2427c99aa385178c630e29f671299cdd9c104f1c885Jordan Rose file_system_it->second->GetFileSystemInfo())); 243740d490593e0de8732a697c9f77b90ddd463863bJordan Rose return true; 244740d490593e0de8732a697c9f77b90ddd463863bJordan Rose} 2457c99aa385178c630e29f671299cdd9c104f1c885Jordan Rose 246740d490593e0de8732a697c9f77b90ddd463863bJordan Rosestd::vector<ProvidedFileSystemInfo> Service::GetProvidedFileSystemInfoList() { 2477c99aa385178c630e29f671299cdd9c104f1c885Jordan Rose DCHECK(thread_checker_.CalledOnValidThread()); 248740d490593e0de8732a697c9f77b90ddd463863bJordan Rose 249740d490593e0de8732a697c9f77b90ddd463863bJordan Rose std::vector<ProvidedFileSystemInfo> result; 250740d490593e0de8732a697c9f77b90ddd463863bJordan Rose for (ProvidedFileSystemMap::const_iterator it = file_system_map_.begin(); 251740d490593e0de8732a697c9f77b90ddd463863bJordan Rose it != file_system_map_.end(); 2522f3017f9cbd3774f690c979410bfec38423d03afJordan Rose ++it) { 2532f3017f9cbd3774f690c979410bfec38423d03afJordan Rose result.push_back(it->second->GetFileSystemInfo()); 2542f3017f9cbd3774f690c979410bfec38423d03afJordan Rose } 2552f3017f9cbd3774f690c979410bfec38423d03afJordan Rose return result; 2562f3017f9cbd3774f690c979410bfec38423d03afJordan Rose} 2572f3017f9cbd3774f690c979410bfec38423d03afJordan Rose 258740d490593e0de8732a697c9f77b90ddd463863bJordan RoseProvidedFileSystemInterface* Service::GetProvidedFileSystem( 259740d490593e0de8732a697c9f77b90ddd463863bJordan Rose const std::string& extension_id, 260740d490593e0de8732a697c9f77b90ddd463863bJordan Rose const std::string& file_system_id) { 26185d7e01cf639b257d70f8a129709a2d7594d7b22Jordan Rose DCHECK(thread_checker_.CalledOnValidThread()); 26285d7e01cf639b257d70f8a129709a2d7594d7b22Jordan Rose 26385d7e01cf639b257d70f8a129709a2d7594d7b22Jordan Rose const ProvidedFileSystemMap::const_iterator file_system_it = 26485d7e01cf639b257d70f8a129709a2d7594d7b22Jordan Rose file_system_map_.find(FileSystemKey(extension_id, file_system_id)); 26585d7e01cf639b257d70f8a129709a2d7594d7b22Jordan Rose if (file_system_it == file_system_map_.end()) 2667c99aa385178c630e29f671299cdd9c104f1c885Jordan Rose return NULL; 2677c99aa385178c630e29f671299cdd9c104f1c885Jordan Rose 2687c99aa385178c630e29f671299cdd9c104f1c885Jordan Rose return file_system_it->second; 26985d7e01cf639b257d70f8a129709a2d7594d7b22Jordan Rose} 2702f3017f9cbd3774f690c979410bfec38423d03afJordan Rose 2712f3017f9cbd3774f690c979410bfec38423d03afJordan Rosevoid Service::OnExtensionUnloaded( 2722f3017f9cbd3774f690c979410bfec38423d03afJordan Rose content::BrowserContext* browser_context, 2732f3017f9cbd3774f690c979410bfec38423d03afJordan Rose const extensions::Extension* extension, 2742f3017f9cbd3774f690c979410bfec38423d03afJordan Rose extensions::UnloadedExtensionInfo::Reason reason) { 2752f3017f9cbd3774f690c979410bfec38423d03afJordan Rose // Unmount all of the provided file systems associated with this extension. 2762f3017f9cbd3774f690c979410bfec38423d03afJordan Rose ProvidedFileSystemMap::iterator it = file_system_map_.begin(); 2772f3017f9cbd3774f690c979410bfec38423d03afJordan Rose while (it != file_system_map_.end()) { 2782f3017f9cbd3774f690c979410bfec38423d03afJordan Rose const ProvidedFileSystemInfo& file_system_info = 2792f3017f9cbd3774f690c979410bfec38423d03afJordan Rose it->second->GetFileSystemInfo(); 2802f3017f9cbd3774f690c979410bfec38423d03afJordan Rose // Advance the iterator beforehand, otherwise it will become invalidated 2812f3017f9cbd3774f690c979410bfec38423d03afJordan Rose // by the UnmountFileSystem() call. 2822f3017f9cbd3774f690c979410bfec38423d03afJordan Rose ++it; 2832f3017f9cbd3774f690c979410bfec38423d03afJordan Rose if (file_system_info.extension_id() == extension->id()) { 2842f3017f9cbd3774f690c979410bfec38423d03afJordan Rose const bool unmount_result = UnmountFileSystem( 2852f3017f9cbd3774f690c979410bfec38423d03afJordan Rose file_system_info.extension_id(), 2862f3017f9cbd3774f690c979410bfec38423d03afJordan Rose file_system_info.file_system_id(), 2872f3017f9cbd3774f690c979410bfec38423d03afJordan Rose reason == extensions::UnloadedExtensionInfo::REASON_PROFILE_SHUTDOWN 2882f3017f9cbd3774f690c979410bfec38423d03afJordan Rose ? UNMOUNT_REASON_SHUTDOWN 2892f3017f9cbd3774f690c979410bfec38423d03afJordan Rose : UNMOUNT_REASON_USER); 2902f3017f9cbd3774f690c979410bfec38423d03afJordan Rose DCHECK(unmount_result); 2912f3017f9cbd3774f690c979410bfec38423d03afJordan Rose } 2922f3017f9cbd3774f690c979410bfec38423d03afJordan Rose } 2932f3017f9cbd3774f690c979410bfec38423d03afJordan Rose} 2942f3017f9cbd3774f690c979410bfec38423d03afJordan Rose 2952f3017f9cbd3774f690c979410bfec38423d03afJordan Rosevoid Service::OnExtensionLoaded(content::BrowserContext* browser_context, 2962f3017f9cbd3774f690c979410bfec38423d03afJordan Rose const extensions::Extension* extension) { 2972f3017f9cbd3774f690c979410bfec38423d03afJordan Rose RestoreFileSystems(extension->id()); 2982f3017f9cbd3774f690c979410bfec38423d03afJordan Rose} 2992f3017f9cbd3774f690c979410bfec38423d03afJordan Rose 3002f3017f9cbd3774f690c979410bfec38423d03afJordan RoseProvidedFileSystemInterface* Service::GetProvidedFileSystem( 3012f3017f9cbd3774f690c979410bfec38423d03afJordan Rose const std::string& mount_point_name) { 30228038f33aa2db4833881fea757a1f0daf85ac02bJordan Rose DCHECK(thread_checker_.CalledOnValidThread()); 3038d276d38c258dfc572586daf6c0e8f8fce249c0eJordan Rose 30428038f33aa2db4833881fea757a1f0daf85ac02bJordan Rose const MountPointNameToKeyMap::const_iterator mapping_it = 30528038f33aa2db4833881fea757a1f0daf85ac02bJordan Rose mount_point_name_to_key_map_.find(mount_point_name); 306740d490593e0de8732a697c9f77b90ddd463863bJordan Rose if (mapping_it == mount_point_name_to_key_map_.end()) 307740d490593e0de8732a697c9f77b90ddd463863bJordan Rose return NULL; 308740d490593e0de8732a697c9f77b90ddd463863bJordan Rose 309740d490593e0de8732a697c9f77b90ddd463863bJordan Rose const ProvidedFileSystemMap::const_iterator file_system_it = 310740d490593e0de8732a697c9f77b90ddd463863bJordan Rose file_system_map_.find(mapping_it->second); 311740d490593e0de8732a697c9f77b90ddd463863bJordan Rose if (file_system_it == file_system_map_.end()) 312740d490593e0de8732a697c9f77b90ddd463863bJordan Rose return NULL; 313ef15831780b705475e7b237ac16418e9b53cb7a6Jordan Rose 314ef15831780b705475e7b237ac16418e9b53cb7a6Jordan Rose return file_system_it->second; 315ef15831780b705475e7b237ac16418e9b53cb7a6Jordan Rose} 316ef15831780b705475e7b237ac16418e9b53cb7a6Jordan Rose 317ef15831780b705475e7b237ac16418e9b53cb7a6Jordan Rosevoid Service::OnRequestUnmountStatus( 318ef15831780b705475e7b237ac16418e9b53cb7a6Jordan Rose const ProvidedFileSystemInfo& file_system_info, 319ef15831780b705475e7b237ac16418e9b53cb7a6Jordan Rose base::File::Error error) { 320ef15831780b705475e7b237ac16418e9b53cb7a6Jordan Rose // Notify observers about failure in unmounting, since mount() will not be 321972a3680bdd95f2e9d6316b391f1c47513dc78ccJordan Rose // called by the provided file system. In case of success mount() will be 322972a3680bdd95f2e9d6316b391f1c47513dc78ccJordan Rose // invoked, and observers notified, so there is no need to call them now. 323d563d3fb73879df7147b8a5302c3bf0e1402ba18Jordan Rose if (error != base::File::FILE_OK) { 324972a3680bdd95f2e9d6316b391f1c47513dc78ccJordan Rose FOR_EACH_OBSERVER(Observer, 325972a3680bdd95f2e9d6316b391f1c47513dc78ccJordan Rose observers_, 326d563d3fb73879df7147b8a5302c3bf0e1402ba18Jordan Rose OnProvidedFileSystemUnmount(file_system_info, error)); 327972a3680bdd95f2e9d6316b391f1c47513dc78ccJordan Rose } 328972a3680bdd95f2e9d6316b391f1c47513dc78ccJordan Rose} 329972a3680bdd95f2e9d6316b391f1c47513dc78ccJordan Rose 3306062334cc388bce69fb3978c4ecb26c6485a5c2bJordan Rosevoid Service::RememberFileSystem( 3316062334cc388bce69fb3978c4ecb26c6485a5c2bJordan Rose const ProvidedFileSystemInfo& file_system_info) { 3326062334cc388bce69fb3978c4ecb26c6485a5c2bJordan Rose base::DictionaryValue* file_system = new base::DictionaryValue(); 33385d7e01cf639b257d70f8a129709a2d7594d7b22Jordan Rose file_system->SetStringWithoutPathExpansion(kPrefKeyFileSystemId, 33416e6a7cb41319459ded69b4d47f405c1035dd347Anna Zaks file_system_info.file_system_id()); 33516e6a7cb41319459ded69b4d47f405c1035dd347Anna Zaks file_system->SetStringWithoutPathExpansion(kPrefKeyDisplayName, 33616e6a7cb41319459ded69b4d47f405c1035dd347Anna Zaks file_system_info.display_name()); 337e54cfc7b9990acffd0a8a4ba381717b4bb9f3011Jordan Rose file_system->SetBooleanWithoutPathExpansion(kPrefKeyWritable, 338740d490593e0de8732a697c9f77b90ddd463863bJordan Rose file_system_info.writable()); 339740d490593e0de8732a697c9f77b90ddd463863bJordan Rose 340740d490593e0de8732a697c9f77b90ddd463863bJordan Rose PrefService* const pref_service = profile_->GetPrefs(); 341740d490593e0de8732a697c9f77b90ddd463863bJordan Rose DCHECK(pref_service); 342e54cfc7b9990acffd0a8a4ba381717b4bb9f3011Jordan Rose 343e54cfc7b9990acffd0a8a4ba381717b4bb9f3011Jordan Rose DictionaryPrefUpdate dict_update(pref_service, 344e54cfc7b9990acffd0a8a4ba381717b4bb9f3011Jordan Rose prefs::kFileSystemProviderMounted); 345e54cfc7b9990acffd0a8a4ba381717b4bb9f3011Jordan Rose 346e54cfc7b9990acffd0a8a4ba381717b4bb9f3011Jordan Rose base::DictionaryValue* file_systems_per_extension = NULL; 347e54cfc7b9990acffd0a8a4ba381717b4bb9f3011Jordan Rose if (!dict_update->GetDictionaryWithoutPathExpansion( 348e54cfc7b9990acffd0a8a4ba381717b4bb9f3011Jordan Rose file_system_info.extension_id(), &file_systems_per_extension)) { 349e54cfc7b9990acffd0a8a4ba381717b4bb9f3011Jordan Rose file_systems_per_extension = new base::DictionaryValue(); 350e54cfc7b9990acffd0a8a4ba381717b4bb9f3011Jordan Rose dict_update->SetWithoutPathExpansion(file_system_info.extension_id(), 351e54cfc7b9990acffd0a8a4ba381717b4bb9f3011Jordan Rose file_systems_per_extension); 352e54cfc7b9990acffd0a8a4ba381717b4bb9f3011Jordan Rose } 353e54cfc7b9990acffd0a8a4ba381717b4bb9f3011Jordan Rose 354e54cfc7b9990acffd0a8a4ba381717b4bb9f3011Jordan Rose file_systems_per_extension->SetWithoutPathExpansion( 355e54cfc7b9990acffd0a8a4ba381717b4bb9f3011Jordan Rose file_system_info.file_system_id(), file_system); 356e54cfc7b9990acffd0a8a4ba381717b4bb9f3011Jordan Rose} 357e54cfc7b9990acffd0a8a4ba381717b4bb9f3011Jordan Rose 358ef15831780b705475e7b237ac16418e9b53cb7a6Jordan Rosevoid Service::ForgetFileSystem(const std::string& extension_id, 359e54cfc7b9990acffd0a8a4ba381717b4bb9f3011Jordan Rose const std::string& file_system_id) { 360ef15831780b705475e7b237ac16418e9b53cb7a6Jordan Rose PrefService* const pref_service = profile_->GetPrefs(); 361e54cfc7b9990acffd0a8a4ba381717b4bb9f3011Jordan Rose DCHECK(pref_service); 362740d490593e0de8732a697c9f77b90ddd463863bJordan Rose 363740d490593e0de8732a697c9f77b90ddd463863bJordan Rose DictionaryPrefUpdate dict_update(pref_service, 364740d490593e0de8732a697c9f77b90ddd463863bJordan Rose prefs::kFileSystemProviderMounted); 365e54cfc7b9990acffd0a8a4ba381717b4bb9f3011Jordan Rose 366e54cfc7b9990acffd0a8a4ba381717b4bb9f3011Jordan Rose base::DictionaryValue* file_systems_per_extension = NULL; 367e54cfc7b9990acffd0a8a4ba381717b4bb9f3011Jordan Rose if (!dict_update->GetDictionaryWithoutPathExpansion( 368e54cfc7b9990acffd0a8a4ba381717b4bb9f3011Jordan Rose extension_id, &file_systems_per_extension)) 369e54cfc7b9990acffd0a8a4ba381717b4bb9f3011Jordan Rose return; // Nothing to forget. 370740d490593e0de8732a697c9f77b90ddd463863bJordan Rose 371740d490593e0de8732a697c9f77b90ddd463863bJordan Rose file_systems_per_extension->RemoveWithoutPathExpansion(file_system_id, NULL); 372740d490593e0de8732a697c9f77b90ddd463863bJordan Rose if (!file_systems_per_extension->size()) 373740d490593e0de8732a697c9f77b90ddd463863bJordan Rose dict_update->Remove(extension_id, NULL); 374e54cfc7b9990acffd0a8a4ba381717b4bb9f3011Jordan Rose} 375740d490593e0de8732a697c9f77b90ddd463863bJordan Rose 376740d490593e0de8732a697c9f77b90ddd463863bJordan Rosevoid Service::RestoreFileSystems(const std::string& extension_id) { 377740d490593e0de8732a697c9f77b90ddd463863bJordan Rose PrefService* const pref_service = profile_->GetPrefs(); 378740d490593e0de8732a697c9f77b90ddd463863bJordan Rose DCHECK(pref_service); 3790ffbfd1a7f80f9a3c07317cb8f44c562f2ba1ba5Jordan Rose 380b7a23e05d1d8f07f2a6edce5c88c728fe894c2c7Jordan Rose const base::DictionaryValue* const file_systems = 38142c72c258e08ca79c9267346b4badcddd8fcd001Benjamin Kramer pref_service->GetDictionary(prefs::kFileSystemProviderMounted); 382740d490593e0de8732a697c9f77b90ddd463863bJordan Rose DCHECK(file_systems); 383740d490593e0de8732a697c9f77b90ddd463863bJordan Rose 384b7a23e05d1d8f07f2a6edce5c88c728fe894c2c7Jordan Rose const base::DictionaryValue* file_systems_per_extension = NULL; 385740d490593e0de8732a697c9f77b90ddd463863bJordan Rose if (!file_systems->GetDictionaryWithoutPathExpansion( 386740d490593e0de8732a697c9f77b90ddd463863bJordan Rose extension_id, &file_systems_per_extension)) 387740d490593e0de8732a697c9f77b90ddd463863bJordan Rose return; // Nothing to restore. 388740d490593e0de8732a697c9f77b90ddd463863bJordan Rose 389b7a23e05d1d8f07f2a6edce5c88c728fe894c2c7Jordan Rose // Use a copy of the dictionary, since the original one may be modified while 3907c99aa385178c630e29f671299cdd9c104f1c885Jordan Rose // iterating over it. 3917c99aa385178c630e29f671299cdd9c104f1c885Jordan Rose scoped_ptr<const base::DictionaryValue> file_systems_per_extension_copy( 392b7a23e05d1d8f07f2a6edce5c88c728fe894c2c7Jordan Rose file_systems_per_extension->DeepCopy()); 3937c99aa385178c630e29f671299cdd9c104f1c885Jordan Rose 3947c99aa385178c630e29f671299cdd9c104f1c885Jordan Rose for (base::DictionaryValue::Iterator it(*file_systems_per_extension_copy); 395972a3680bdd95f2e9d6316b391f1c47513dc78ccJordan Rose !it.IsAtEnd(); 396740d490593e0de8732a697c9f77b90ddd463863bJordan Rose it.Advance()) { 397740d490593e0de8732a697c9f77b90ddd463863bJordan Rose const base::Value* file_system_value = NULL; 398b7a23e05d1d8f07f2a6edce5c88c728fe894c2c7Jordan Rose const base::DictionaryValue* file_system = NULL; 399b7a23e05d1d8f07f2a6edce5c88c728fe894c2c7Jordan Rose file_systems_per_extension_copy->GetWithoutPathExpansion( 4007c99aa385178c630e29f671299cdd9c104f1c885Jordan Rose it.key(), &file_system_value); 4017c99aa385178c630e29f671299cdd9c104f1c885Jordan Rose DCHECK(file_system_value); 402b7a23e05d1d8f07f2a6edce5c88c728fe894c2c7Jordan Rose 403740d490593e0de8732a697c9f77b90ddd463863bJordan Rose std::string file_system_id; 404ddc0c4814788dda4ef224cd4d22d07154a6ede49Ted Kremenek std::string display_name; 405ee158bc29bc12ce544996f7cdfde14aba63acf4dJordan Rose bool writable; 406a43df9539644bf1c258e12710cd69d79b0b078cdTed Kremenek 407a43df9539644bf1c258e12710cd69d79b0b078cdTed Kremenek if (!file_system_value->GetAsDictionary(&file_system) || 408a43df9539644bf1c258e12710cd69d79b0b078cdTed Kremenek !file_system->GetStringWithoutPathExpansion(kPrefKeyFileSystemId, 409ddc0c4814788dda4ef224cd4d22d07154a6ede49Ted Kremenek &file_system_id) || 410ddc0c4814788dda4ef224cd4d22d07154a6ede49Ted Kremenek !file_system->GetStringWithoutPathExpansion(kPrefKeyDisplayName, 411ddc0c4814788dda4ef224cd4d22d07154a6ede49Ted Kremenek &display_name) || 412a43df9539644bf1c258e12710cd69d79b0b078cdTed Kremenek !file_system->GetBooleanWithoutPathExpansion(kPrefKeyWritable, 413a43df9539644bf1c258e12710cd69d79b0b078cdTed Kremenek &writable) || 414a43df9539644bf1c258e12710cd69d79b0b078cdTed Kremenek file_system_id.empty() || display_name.empty()) { 415a43df9539644bf1c258e12710cd69d79b0b078cdTed Kremenek LOG(ERROR) 416e90d3f847dcce76237078b67db8895eb7a24189eAnna Zaks << "Malformed provided file system information in preferences."; 417ee158bc29bc12ce544996f7cdfde14aba63acf4dJordan Rose continue; 418ee158bc29bc12ce544996f7cdfde14aba63acf4dJordan Rose } 4197c99aa385178c630e29f671299cdd9c104f1c885Jordan Rose 420b7a23e05d1d8f07f2a6edce5c88c728fe894c2c7Jordan Rose const bool result = 421ef15831780b705475e7b237ac16418e9b53cb7a6Jordan Rose MountFileSystem(extension_id, file_system_id, display_name, writable); 422ef15831780b705475e7b237ac16418e9b53cb7a6Jordan Rose if (!result) { 423ef15831780b705475e7b237ac16418e9b53cb7a6Jordan Rose LOG(ERROR) << "Failed to restore a provided file system from " 424ef15831780b705475e7b237ac16418e9b53cb7a6Jordan Rose << "preferences: " << extension_id << ", " << file_system_id 425ef15831780b705475e7b237ac16418e9b53cb7a6Jordan Rose << ", " << display_name << "."; 426b7a23e05d1d8f07f2a6edce5c88c728fe894c2c7Jordan Rose // Since remounting of the file system failed, then remove it from 427740d490593e0de8732a697c9f77b90ddd463863bJordan Rose // preferences to avoid remounting it over and over again with a failure. 428740d490593e0de8732a697c9f77b90ddd463863bJordan Rose ForgetFileSystem(extension_id, file_system_id); 429740d490593e0de8732a697c9f77b90ddd463863bJordan Rose } 430740d490593e0de8732a697c9f77b90ddd463863bJordan Rose } 431740d490593e0de8732a697c9f77b90ddd463863bJordan Rose} 432740d490593e0de8732a697c9f77b90ddd463863bJordan Rose 433645baeed6800f952e9ad1d5666e01080385531a2Jordan Rose} // namespace file_system_provider 434740d490593e0de8732a697c9f77b90ddd463863bJordan Rose} // namespace chromeos 435740d490593e0de8732a697c9f77b90ddd463863bJordan Rose