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 "storage/browser/fileapi/plugin_private_file_system_backend.h" 6 7 #include <map> 8 9 #include "base/stl_util.h" 10 #include "base/synchronization/lock.h" 11 #include "base/task_runner_util.h" 12 #include "net/base/net_util.h" 13 #include "storage/browser/blob/file_stream_reader.h" 14 #include "storage/browser/fileapi/async_file_util_adapter.h" 15 #include "storage/browser/fileapi/file_stream_writer.h" 16 #include "storage/browser/fileapi/file_system_context.h" 17 #include "storage/browser/fileapi/file_system_operation.h" 18 #include "storage/browser/fileapi/file_system_operation_context.h" 19 #include "storage/browser/fileapi/file_system_options.h" 20 #include "storage/browser/fileapi/isolated_context.h" 21 #include "storage/browser/fileapi/obfuscated_file_util.h" 22 #include "storage/browser/fileapi/quota/quota_reservation.h" 23 #include "storage/common/fileapi/file_system_util.h" 24 25 namespace storage { 26 27 class PluginPrivateFileSystemBackend::FileSystemIDToPluginMap { 28 public: 29 explicit FileSystemIDToPluginMap(base::SequencedTaskRunner* task_runner) 30 : task_runner_(task_runner) {} 31 ~FileSystemIDToPluginMap() {} 32 33 std::string GetPluginIDForURL(const FileSystemURL& url) { 34 DCHECK(task_runner_->RunsTasksOnCurrentThread()); 35 Map::iterator found = map_.find(url.filesystem_id()); 36 if (url.type() != kFileSystemTypePluginPrivate || found == map_.end()) { 37 NOTREACHED() << "Unsupported url is given: " << url.DebugString(); 38 return std::string(); 39 } 40 return found->second; 41 } 42 43 void RegisterFileSystem(const std::string& filesystem_id, 44 const std::string& plugin_id) { 45 DCHECK(task_runner_->RunsTasksOnCurrentThread()); 46 DCHECK(!filesystem_id.empty()); 47 DCHECK(!ContainsKey(map_, filesystem_id)) << filesystem_id; 48 map_[filesystem_id] = plugin_id; 49 } 50 51 void RemoveFileSystem(const std::string& filesystem_id) { 52 DCHECK(task_runner_->RunsTasksOnCurrentThread()); 53 map_.erase(filesystem_id); 54 } 55 56 private: 57 typedef std::map<std::string, std::string> Map; 58 scoped_refptr<base::SequencedTaskRunner> task_runner_; 59 Map map_; 60 }; 61 62 namespace { 63 64 const base::FilePath::CharType* kFileSystemDirectory = 65 SandboxFileSystemBackendDelegate::kFileSystemDirectory; 66 const base::FilePath::CharType* kPluginPrivateDirectory = 67 FILE_PATH_LITERAL("Plugins"); 68 69 base::File::Error OpenFileSystemOnFileTaskRunner( 70 ObfuscatedFileUtil* file_util, 71 PluginPrivateFileSystemBackend::FileSystemIDToPluginMap* plugin_map, 72 const GURL& origin_url, 73 const std::string& filesystem_id, 74 const std::string& plugin_id, 75 OpenFileSystemMode mode) { 76 base::File::Error error = base::File::FILE_ERROR_FAILED; 77 const bool create = (mode == OPEN_FILE_SYSTEM_CREATE_IF_NONEXISTENT); 78 file_util->GetDirectoryForOriginAndType( 79 origin_url, plugin_id, create, &error); 80 if (error == base::File::FILE_OK) 81 plugin_map->RegisterFileSystem(filesystem_id, plugin_id); 82 return error; 83 } 84 85 } // namespace 86 87 PluginPrivateFileSystemBackend::PluginPrivateFileSystemBackend( 88 base::SequencedTaskRunner* file_task_runner, 89 const base::FilePath& profile_path, 90 storage::SpecialStoragePolicy* special_storage_policy, 91 const FileSystemOptions& file_system_options) 92 : file_task_runner_(file_task_runner), 93 file_system_options_(file_system_options), 94 base_path_(profile_path.Append(kFileSystemDirectory) 95 .Append(kPluginPrivateDirectory)), 96 plugin_map_(new FileSystemIDToPluginMap(file_task_runner)), 97 weak_factory_(this) { 98 file_util_.reset( 99 new AsyncFileUtilAdapter(new ObfuscatedFileUtil( 100 special_storage_policy, 101 base_path_, file_system_options.env_override(), 102 file_task_runner, 103 base::Bind(&FileSystemIDToPluginMap::GetPluginIDForURL, 104 base::Owned(plugin_map_)), 105 std::set<std::string>(), 106 NULL))); 107 } 108 109 PluginPrivateFileSystemBackend::~PluginPrivateFileSystemBackend() { 110 if (!file_task_runner_->RunsTasksOnCurrentThread()) { 111 AsyncFileUtil* file_util = file_util_.release(); 112 if (!file_task_runner_->DeleteSoon(FROM_HERE, file_util)) 113 delete file_util; 114 } 115 } 116 117 void PluginPrivateFileSystemBackend::OpenPrivateFileSystem( 118 const GURL& origin_url, 119 FileSystemType type, 120 const std::string& filesystem_id, 121 const std::string& plugin_id, 122 OpenFileSystemMode mode, 123 const StatusCallback& callback) { 124 if (!CanHandleType(type) || file_system_options_.is_incognito()) { 125 base::MessageLoopProxy::current()->PostTask( 126 FROM_HERE, base::Bind(callback, base::File::FILE_ERROR_SECURITY)); 127 return; 128 } 129 130 PostTaskAndReplyWithResult( 131 file_task_runner_.get(), 132 FROM_HERE, 133 base::Bind(&OpenFileSystemOnFileTaskRunner, 134 obfuscated_file_util(), plugin_map_, 135 origin_url, filesystem_id, plugin_id, mode), 136 callback); 137 } 138 139 bool PluginPrivateFileSystemBackend::CanHandleType(FileSystemType type) const { 140 return type == kFileSystemTypePluginPrivate; 141 } 142 143 void PluginPrivateFileSystemBackend::Initialize(FileSystemContext* context) { 144 } 145 146 void PluginPrivateFileSystemBackend::ResolveURL( 147 const FileSystemURL& url, 148 OpenFileSystemMode mode, 149 const OpenFileSystemCallback& callback) { 150 // We never allow opening a new plugin-private filesystem via usual 151 // ResolveURL. 152 base::MessageLoopProxy::current()->PostTask( 153 FROM_HERE, 154 base::Bind(callback, GURL(), std::string(), 155 base::File::FILE_ERROR_SECURITY)); 156 } 157 158 AsyncFileUtil* 159 PluginPrivateFileSystemBackend::GetAsyncFileUtil(FileSystemType type) { 160 return file_util_.get(); 161 } 162 163 WatcherManager* PluginPrivateFileSystemBackend::GetWatcherManager( 164 FileSystemType type) { 165 return NULL; 166 } 167 168 CopyOrMoveFileValidatorFactory* 169 PluginPrivateFileSystemBackend::GetCopyOrMoveFileValidatorFactory( 170 FileSystemType type, 171 base::File::Error* error_code) { 172 DCHECK(error_code); 173 *error_code = base::File::FILE_OK; 174 return NULL; 175 } 176 177 FileSystemOperation* PluginPrivateFileSystemBackend::CreateFileSystemOperation( 178 const FileSystemURL& url, 179 FileSystemContext* context, 180 base::File::Error* error_code) const { 181 scoped_ptr<FileSystemOperationContext> operation_context( 182 new FileSystemOperationContext(context)); 183 return FileSystemOperation::Create(url, context, operation_context.Pass()); 184 } 185 186 bool PluginPrivateFileSystemBackend::SupportsStreaming( 187 const storage::FileSystemURL& url) const { 188 return false; 189 } 190 191 bool PluginPrivateFileSystemBackend::HasInplaceCopyImplementation( 192 storage::FileSystemType type) const { 193 return false; 194 } 195 196 scoped_ptr<storage::FileStreamReader> 197 PluginPrivateFileSystemBackend::CreateFileStreamReader( 198 const FileSystemURL& url, 199 int64 offset, 200 int64 max_bytes_to_read, 201 const base::Time& expected_modification_time, 202 FileSystemContext* context) const { 203 return scoped_ptr<storage::FileStreamReader>(); 204 } 205 206 scoped_ptr<FileStreamWriter> 207 PluginPrivateFileSystemBackend::CreateFileStreamWriter( 208 const FileSystemURL& url, 209 int64 offset, 210 FileSystemContext* context) const { 211 return scoped_ptr<FileStreamWriter>(); 212 } 213 214 FileSystemQuotaUtil* PluginPrivateFileSystemBackend::GetQuotaUtil() { 215 return this; 216 } 217 218 base::File::Error 219 PluginPrivateFileSystemBackend::DeleteOriginDataOnFileTaskRunner( 220 FileSystemContext* context, 221 storage::QuotaManagerProxy* proxy, 222 const GURL& origin_url, 223 FileSystemType type) { 224 if (!CanHandleType(type)) 225 return base::File::FILE_ERROR_SECURITY; 226 bool result = obfuscated_file_util()->DeleteDirectoryForOriginAndType( 227 origin_url, std::string()); 228 if (result) 229 return base::File::FILE_OK; 230 return base::File::FILE_ERROR_FAILED; 231 } 232 233 void PluginPrivateFileSystemBackend::GetOriginsForTypeOnFileTaskRunner( 234 FileSystemType type, 235 std::set<GURL>* origins) { 236 if (!CanHandleType(type)) 237 return; 238 scoped_ptr<ObfuscatedFileUtil::AbstractOriginEnumerator> enumerator( 239 obfuscated_file_util()->CreateOriginEnumerator()); 240 GURL origin; 241 while (!(origin = enumerator->Next()).is_empty()) 242 origins->insert(origin); 243 } 244 245 void PluginPrivateFileSystemBackend::GetOriginsForHostOnFileTaskRunner( 246 FileSystemType type, 247 const std::string& host, 248 std::set<GURL>* origins) { 249 if (!CanHandleType(type)) 250 return; 251 scoped_ptr<ObfuscatedFileUtil::AbstractOriginEnumerator> enumerator( 252 obfuscated_file_util()->CreateOriginEnumerator()); 253 GURL origin; 254 while (!(origin = enumerator->Next()).is_empty()) { 255 if (host == net::GetHostOrSpecFromURL(origin)) 256 origins->insert(origin); 257 } 258 } 259 260 int64 PluginPrivateFileSystemBackend::GetOriginUsageOnFileTaskRunner( 261 FileSystemContext* context, 262 const GURL& origin_url, 263 FileSystemType type) { 264 // We don't track usage on this filesystem. 265 return 0; 266 } 267 268 scoped_refptr<QuotaReservation> 269 PluginPrivateFileSystemBackend::CreateQuotaReservationOnFileTaskRunner( 270 const GURL& origin_url, 271 FileSystemType type) { 272 // We don't track usage on this filesystem. 273 NOTREACHED(); 274 return scoped_refptr<QuotaReservation>(); 275 } 276 277 const UpdateObserverList* PluginPrivateFileSystemBackend::GetUpdateObservers( 278 FileSystemType type) const { 279 return NULL; 280 } 281 282 const ChangeObserverList* PluginPrivateFileSystemBackend::GetChangeObservers( 283 FileSystemType type) const { 284 return NULL; 285 } 286 287 const AccessObserverList* PluginPrivateFileSystemBackend::GetAccessObservers( 288 FileSystemType type) const { 289 return NULL; 290 } 291 292 ObfuscatedFileUtil* PluginPrivateFileSystemBackend::obfuscated_file_util() { 293 return static_cast<ObfuscatedFileUtil*>( 294 static_cast<AsyncFileUtilAdapter*>(file_util_.get())->sync_file_util()); 295 } 296 297 } // namespace storage 298