1// Copyright (c) 2012 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 "webkit/browser/fileapi/file_system_context.h" 6 7#include "base/bind.h" 8#include "base/single_thread_task_runner.h" 9#include "base/stl_util.h" 10#include "base/task_runner_util.h" 11#include "url/gurl.h" 12#include "webkit/browser/blob/file_stream_reader.h" 13#include "webkit/browser/fileapi/copy_or_move_file_validator.h" 14#include "webkit/browser/fileapi/external_mount_points.h" 15#include "webkit/browser/fileapi/file_permission_policy.h" 16#include "webkit/browser/fileapi/file_stream_writer.h" 17#include "webkit/browser/fileapi/file_system_file_util.h" 18#include "webkit/browser/fileapi/file_system_operation.h" 19#include "webkit/browser/fileapi/file_system_operation_runner.h" 20#include "webkit/browser/fileapi/file_system_options.h" 21#include "webkit/browser/fileapi/file_system_quota_client.h" 22#include "webkit/browser/fileapi/file_system_url.h" 23#include "webkit/browser/fileapi/isolated_context.h" 24#include "webkit/browser/fileapi/isolated_file_system_backend.h" 25#include "webkit/browser/fileapi/mount_points.h" 26#include "webkit/browser/fileapi/sandbox_file_system_backend.h" 27#include "webkit/browser/fileapi/test_file_system_backend.h" 28#include "webkit/browser/quota/quota_manager.h" 29#include "webkit/browser/quota/special_storage_policy.h" 30#include "webkit/common/fileapi/file_system_util.h" 31 32using quota::QuotaClient; 33 34namespace fileapi { 35 36namespace { 37 38QuotaClient* CreateQuotaClient( 39 FileSystemContext* context, 40 bool is_incognito) { 41 return new FileSystemQuotaClient(context, is_incognito); 42} 43 44void DidOpenFileSystem( 45 const FileSystemContext::OpenFileSystemCallback& callback, 46 const GURL& filesystem_root, 47 const std::string& filesystem_name, 48 base::PlatformFileError error) { 49 callback.Run(error, filesystem_name, filesystem_root); 50} 51 52} // namespace 53 54// static 55int FileSystemContext::GetPermissionPolicy(FileSystemType type) { 56 switch (type) { 57 case kFileSystemTypeTemporary: 58 case kFileSystemTypePersistent: 59 case kFileSystemTypeSyncable: 60 return FILE_PERMISSION_SANDBOX; 61 62 case kFileSystemTypeDrive: 63 case kFileSystemTypeNativeForPlatformApp: 64 case kFileSystemTypeNativeLocal: 65 return FILE_PERMISSION_USE_FILE_PERMISSION; 66 67 case kFileSystemTypeRestrictedNativeLocal: 68 return FILE_PERMISSION_READ_ONLY | 69 FILE_PERMISSION_USE_FILE_PERMISSION; 70 71 // Following types are only accessed via IsolatedFileSystem, and 72 // don't have their own permission policies. 73 case kFileSystemTypeDeviceMedia: 74 case kFileSystemTypeDragged: 75 case kFileSystemTypeForTransientFile: 76 case kFileSystemTypeItunes: 77 case kFileSystemTypeNativeMedia: 78 case kFileSystemTypePicasa: 79 return FILE_PERMISSION_ALWAYS_DENY; 80 81 // Following types only appear as mount_type, and will not be 82 // queried for their permission policies. 83 case kFileSystemTypeIsolated: 84 case kFileSystemTypeExternal: 85 return FILE_PERMISSION_ALWAYS_DENY; 86 87 // Following types should not be used to access files by FileAPI clients. 88 case kFileSystemTypeTest: 89 case kFileSystemTypeSyncableForInternalSync: 90 case kFileSystemInternalTypeEnumEnd: 91 case kFileSystemInternalTypeEnumStart: 92 case kFileSystemTypeUnknown: 93 return FILE_PERMISSION_ALWAYS_DENY; 94 } 95 NOTREACHED(); 96 return FILE_PERMISSION_ALWAYS_DENY; 97} 98 99FileSystemContext::FileSystemContext( 100 base::SingleThreadTaskRunner* io_task_runner, 101 base::SequencedTaskRunner* file_task_runner, 102 ExternalMountPoints* external_mount_points, 103 quota::SpecialStoragePolicy* special_storage_policy, 104 quota::QuotaManagerProxy* quota_manager_proxy, 105 ScopedVector<FileSystemBackend> additional_backends, 106 const base::FilePath& partition_path, 107 const FileSystemOptions& options) 108 : io_task_runner_(io_task_runner), 109 default_file_task_runner_(file_task_runner), 110 quota_manager_proxy_(quota_manager_proxy), 111 sandbox_context_(new SandboxContext( 112 quota_manager_proxy, 113 file_task_runner, 114 partition_path, 115 special_storage_policy, 116 options)), 117 sandbox_backend_(new SandboxFileSystemBackend( 118 sandbox_context_.get())), 119 isolated_backend_(new IsolatedFileSystemBackend()), 120 additional_backends_(additional_backends.Pass()), 121 external_mount_points_(external_mount_points), 122 partition_path_(partition_path), 123 operation_runner_(new FileSystemOperationRunner(this)) { 124 if (quota_manager_proxy) { 125 quota_manager_proxy->RegisterClient(CreateQuotaClient( 126 this, options.is_incognito())); 127 } 128 129 RegisterBackend(sandbox_backend_.get()); 130 RegisterBackend(isolated_backend_.get()); 131 132 for (ScopedVector<FileSystemBackend>::const_iterator iter = 133 additional_backends_.begin(); 134 iter != additional_backends_.end(); ++iter) { 135 RegisterBackend(*iter); 136 } 137 138 sandbox_backend_->Initialize(this); 139 isolated_backend_->Initialize(this); 140 for (ScopedVector<FileSystemBackend>::const_iterator iter = 141 additional_backends_.begin(); 142 iter != additional_backends_.end(); ++iter) { 143 (*iter)->Initialize(this); 144 } 145 146 // Additional mount points must be added before regular system-wide 147 // mount points. 148 if (external_mount_points) 149 url_crackers_.push_back(external_mount_points); 150 url_crackers_.push_back(ExternalMountPoints::GetSystemInstance()); 151 url_crackers_.push_back(IsolatedContext::GetInstance()); 152} 153 154bool FileSystemContext::DeleteDataForOriginOnFileThread( 155 const GURL& origin_url) { 156 DCHECK(default_file_task_runner()->RunsTasksOnCurrentThread()); 157 DCHECK(origin_url == origin_url.GetOrigin()); 158 159 bool success = true; 160 for (FileSystemBackendMap::iterator iter = backend_map_.begin(); 161 iter != backend_map_.end(); 162 ++iter) { 163 FileSystemBackend* backend = iter->second; 164 if (!backend->GetQuotaUtil()) 165 continue; 166 if (backend->GetQuotaUtil()->DeleteOriginDataOnFileThread( 167 this, quota_manager_proxy(), origin_url, iter->first) 168 != base::PLATFORM_FILE_OK) { 169 // Continue the loop, but record the failure. 170 success = false; 171 } 172 } 173 174 return success; 175} 176 177void FileSystemContext::Shutdown() { 178 if (!io_task_runner_->RunsTasksOnCurrentThread()) { 179 io_task_runner_->PostTask( 180 FROM_HERE, base::Bind(&FileSystemContext::Shutdown, 181 make_scoped_refptr(this))); 182 return; 183 } 184 operation_runner_->Shutdown(); 185} 186 187FileSystemQuotaUtil* 188FileSystemContext::GetQuotaUtil(FileSystemType type) const { 189 FileSystemBackend* backend = GetFileSystemBackend(type); 190 if (!backend) 191 return NULL; 192 return backend->GetQuotaUtil(); 193} 194 195AsyncFileUtil* FileSystemContext::GetAsyncFileUtil( 196 FileSystemType type) const { 197 FileSystemBackend* backend = GetFileSystemBackend(type); 198 if (!backend) 199 return NULL; 200 return backend->GetAsyncFileUtil(type); 201} 202 203FileSystemFileUtil* FileSystemContext::GetFileUtil( 204 FileSystemType type) const { 205 FileSystemBackend* backend = GetFileSystemBackend(type); 206 if (!backend) 207 return NULL; 208 return backend->GetFileUtil(type); 209} 210 211CopyOrMoveFileValidatorFactory* 212FileSystemContext::GetCopyOrMoveFileValidatorFactory( 213 FileSystemType type, base::PlatformFileError* error_code) const { 214 DCHECK(error_code); 215 *error_code = base::PLATFORM_FILE_OK; 216 FileSystemBackend* backend = GetFileSystemBackend(type); 217 if (!backend) 218 return NULL; 219 return backend->GetCopyOrMoveFileValidatorFactory( 220 type, error_code); 221} 222 223FileSystemBackend* FileSystemContext::GetFileSystemBackend( 224 FileSystemType type) const { 225 FileSystemBackendMap::const_iterator found = backend_map_.find(type); 226 if (found != backend_map_.end()) 227 return found->second; 228 NOTREACHED() << "Unknown filesystem type: " << type; 229 return NULL; 230} 231 232bool FileSystemContext::IsSandboxFileSystem(FileSystemType type) const { 233 return GetQuotaUtil(type) != NULL; 234} 235 236const UpdateObserverList* FileSystemContext::GetUpdateObservers( 237 FileSystemType type) const { 238 FileSystemBackend* backend = GetFileSystemBackend(type); 239 if (backend->GetQuotaUtil()) 240 return backend->GetQuotaUtil()->GetUpdateObservers(type); 241 return NULL; 242} 243 244const AccessObserverList* FileSystemContext::GetAccessObservers( 245 FileSystemType type) const { 246 FileSystemBackend* backend = GetFileSystemBackend(type); 247 if (backend->GetQuotaUtil()) 248 return backend->GetQuotaUtil()->GetAccessObservers(type); 249 return NULL; 250} 251 252void FileSystemContext::GetFileSystemTypes( 253 std::vector<FileSystemType>* types) const { 254 types->clear(); 255 for (FileSystemBackendMap::const_iterator iter = backend_map_.begin(); 256 iter != backend_map_.end(); ++iter) 257 types->push_back(iter->first); 258} 259 260ExternalFileSystemBackend* 261FileSystemContext::external_backend() const { 262 return static_cast<ExternalFileSystemBackend*>( 263 GetFileSystemBackend(kFileSystemTypeExternal)); 264} 265 266void FileSystemContext::OpenFileSystem( 267 const GURL& origin_url, 268 FileSystemType type, 269 OpenFileSystemMode mode, 270 const OpenFileSystemCallback& callback) { 271 DCHECK(!callback.is_null()); 272 273 FileSystemBackend* backend = GetFileSystemBackend(type); 274 if (!backend) { 275 callback.Run(base::PLATFORM_FILE_ERROR_SECURITY, std::string(), GURL()); 276 return; 277 } 278 279 backend->OpenFileSystem(origin_url, type, mode, 280 base::Bind(&DidOpenFileSystem, callback)); 281} 282 283void FileSystemContext::DeleteFileSystem( 284 const GURL& origin_url, 285 FileSystemType type, 286 const DeleteFileSystemCallback& callback) { 287 DCHECK(origin_url == origin_url.GetOrigin()); 288 FileSystemBackend* backend = GetFileSystemBackend(type); 289 if (!backend) { 290 callback.Run(base::PLATFORM_FILE_ERROR_SECURITY); 291 return; 292 } 293 if (!backend->GetQuotaUtil()) { 294 callback.Run(base::PLATFORM_FILE_ERROR_INVALID_OPERATION); 295 return; 296 } 297 298 base::PostTaskAndReplyWithResult( 299 default_file_task_runner(), 300 FROM_HERE, 301 // It is safe to pass Unretained(quota_util) since context owns it. 302 base::Bind(&FileSystemQuotaUtil::DeleteOriginDataOnFileThread, 303 base::Unretained(backend->GetQuotaUtil()), 304 make_scoped_refptr(this), 305 base::Unretained(quota_manager_proxy()), 306 origin_url, 307 type), 308 callback); 309} 310 311scoped_ptr<webkit_blob::FileStreamReader> 312FileSystemContext::CreateFileStreamReader( 313 const FileSystemURL& url, 314 int64 offset, 315 const base::Time& expected_modification_time) { 316 if (!url.is_valid()) 317 return scoped_ptr<webkit_blob::FileStreamReader>(); 318 FileSystemBackend* backend = GetFileSystemBackend(url.type()); 319 if (!backend) 320 return scoped_ptr<webkit_blob::FileStreamReader>(); 321 return backend->CreateFileStreamReader( 322 url, offset, expected_modification_time, this); 323} 324 325scoped_ptr<FileStreamWriter> FileSystemContext::CreateFileStreamWriter( 326 const FileSystemURL& url, 327 int64 offset) { 328 if (!url.is_valid()) 329 return scoped_ptr<FileStreamWriter>(); 330 FileSystemBackend* backend = GetFileSystemBackend(url.type()); 331 if (!backend) 332 return scoped_ptr<FileStreamWriter>(); 333 return backend->CreateFileStreamWriter(url, offset, this); 334} 335 336scoped_ptr<FileSystemOperationRunner> 337FileSystemContext::CreateFileSystemOperationRunner() { 338 return make_scoped_ptr(new FileSystemOperationRunner(this)); 339} 340 341FileSystemURL FileSystemContext::CrackURL(const GURL& url) const { 342 return CrackFileSystemURL(FileSystemURL(url)); 343} 344 345FileSystemURL FileSystemContext::CreateCrackedFileSystemURL( 346 const GURL& origin, 347 FileSystemType type, 348 const base::FilePath& path) const { 349 return CrackFileSystemURL(FileSystemURL(origin, type, path)); 350} 351 352#if defined(OS_CHROMEOS) && defined(GOOGLE_CHROME_BUILD) 353void FileSystemContext::EnableTemporaryFileSystemInIncognito() { 354 sandbox_backend_->set_enable_temporary_file_system_in_incognito(true); 355} 356#endif 357 358FileSystemContext::~FileSystemContext() { 359} 360 361void FileSystemContext::DeleteOnCorrectThread() const { 362 if (!io_task_runner_->RunsTasksOnCurrentThread() && 363 io_task_runner_->DeleteSoon(FROM_HERE, this)) { 364 return; 365 } 366 delete this; 367} 368 369FileSystemOperation* FileSystemContext::CreateFileSystemOperation( 370 const FileSystemURL& url, base::PlatformFileError* error_code) { 371 if (!url.is_valid()) { 372 if (error_code) 373 *error_code = base::PLATFORM_FILE_ERROR_INVALID_URL; 374 return NULL; 375 } 376 377 FileSystemBackend* backend = GetFileSystemBackend(url.type()); 378 if (!backend) { 379 if (error_code) 380 *error_code = base::PLATFORM_FILE_ERROR_FAILED; 381 return NULL; 382 } 383 384 base::PlatformFileError fs_error = base::PLATFORM_FILE_OK; 385 FileSystemOperation* operation = 386 backend->CreateFileSystemOperation(url, this, &fs_error); 387 388 if (error_code) 389 *error_code = fs_error; 390 return operation; 391} 392 393FileSystemURL FileSystemContext::CrackFileSystemURL( 394 const FileSystemURL& url) const { 395 if (!url.is_valid()) 396 return FileSystemURL(); 397 398 // The returned value in case there is no crackers which can crack the url. 399 // This is valid situation for non isolated/external file systems. 400 FileSystemURL current = url; 401 402 // File system may be mounted multiple times (e.g., an isolated filesystem on 403 // top of an external filesystem). Hence cracking needs to be iterated. 404 for (;;) { 405 FileSystemURL cracked = current; 406 for (size_t i = 0; i < url_crackers_.size(); ++i) { 407 if (!url_crackers_[i]->HandlesFileSystemMountType(current.type())) 408 continue; 409 cracked = url_crackers_[i]->CrackFileSystemURL(current); 410 if (cracked.is_valid()) 411 break; 412 } 413 if (cracked == current) 414 break; 415 current = cracked; 416 } 417 return current; 418} 419 420void FileSystemContext::RegisterBackend( 421 FileSystemBackend* backend) { 422 const FileSystemType mount_types[] = { 423 kFileSystemTypeTemporary, 424 kFileSystemTypePersistent, 425 kFileSystemTypeIsolated, 426 kFileSystemTypeExternal, 427 }; 428 // Register file system backends for public mount types. 429 for (size_t j = 0; j < ARRAYSIZE_UNSAFE(mount_types); ++j) { 430 if (backend->CanHandleType(mount_types[j])) { 431 const bool inserted = backend_map_.insert( 432 std::make_pair(mount_types[j], backend)).second; 433 DCHECK(inserted); 434 } 435 } 436 // Register file system backends for internal types. 437 for (int t = kFileSystemInternalTypeEnumStart + 1; 438 t < kFileSystemInternalTypeEnumEnd; ++t) { 439 FileSystemType type = static_cast<FileSystemType>(t); 440 if (backend->CanHandleType(type)) { 441 const bool inserted = backend_map_.insert( 442 std::make_pair(type, backend)).second; 443 DCHECK(inserted); 444 } 445 } 446} 447 448} // namespace fileapi 449