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.
5 #include "webkit/browser/fileapi/file_system_context.h"
8 #include "base/single_thread_task_runner.h"
9 #include "base/stl_util.h"
10 #include "base/task_runner_util.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/quota/quota_manager.h"
28 #include "webkit/browser/quota/special_storage_policy.h"
29 #include "webkit/common/fileapi/file_system_info.h"
30 #include "webkit/common/fileapi/file_system_util.h"
32 using quota::QuotaClient;
38 QuotaClient* CreateQuotaClient(
39 FileSystemContext* context,
41 return new FileSystemQuotaClient(context, is_incognito);
45 void DidGetMetadataForResolveURL(
46 const base::FilePath& path,
47 const FileSystemContext::ResolveURLCallback& callback,
48 const FileSystemInfo& info,
49 base::PlatformFileError error,
50 const base::PlatformFileInfo& file_info) {
51 if (error != base::PLATFORM_FILE_OK) {
52 callback.Run(error, FileSystemInfo(), base::FilePath(), false);
55 callback.Run(error, info, path, file_info.is_directory);
61 int FileSystemContext::GetPermissionPolicy(FileSystemType type) {
63 case kFileSystemTypeTemporary:
64 case kFileSystemTypePersistent:
65 case kFileSystemTypeSyncable:
66 return FILE_PERMISSION_SANDBOX;
68 case kFileSystemTypeDrive:
69 case kFileSystemTypeNativeForPlatformApp:
70 case kFileSystemTypeNativeLocal:
71 return FILE_PERMISSION_USE_FILE_PERMISSION;
73 case kFileSystemTypeRestrictedNativeLocal:
74 return FILE_PERMISSION_READ_ONLY |
75 FILE_PERMISSION_USE_FILE_PERMISSION;
77 // Following types are only accessed via IsolatedFileSystem, and
78 // don't have their own permission policies.
79 case kFileSystemTypeDeviceMedia:
80 case kFileSystemTypeDragged:
81 case kFileSystemTypeForTransientFile:
82 case kFileSystemTypeIphoto:
83 case kFileSystemTypeItunes:
84 case kFileSystemTypeNativeMedia:
85 case kFileSystemTypePicasa:
86 case kFileSystemTypePluginPrivate:
87 return FILE_PERMISSION_ALWAYS_DENY;
89 // Following types only appear as mount_type, and will not be
90 // queried for their permission policies.
91 case kFileSystemTypeIsolated:
92 case kFileSystemTypeExternal:
93 return FILE_PERMISSION_ALWAYS_DENY;
95 // Following types should not be used to access files by FileAPI clients.
96 case kFileSystemTypeTest:
97 case kFileSystemTypeSyncableForInternalSync:
98 case kFileSystemInternalTypeEnumEnd:
99 case kFileSystemInternalTypeEnumStart:
100 case kFileSystemTypeUnknown:
101 return FILE_PERMISSION_ALWAYS_DENY;
104 return FILE_PERMISSION_ALWAYS_DENY;
107 FileSystemContext::FileSystemContext(
108 base::SingleThreadTaskRunner* io_task_runner,
109 base::SequencedTaskRunner* file_task_runner,
110 ExternalMountPoints* external_mount_points,
111 quota::SpecialStoragePolicy* special_storage_policy,
112 quota::QuotaManagerProxy* quota_manager_proxy,
113 ScopedVector<FileSystemBackend> additional_backends,
114 const base::FilePath& partition_path,
115 const FileSystemOptions& options)
116 : io_task_runner_(io_task_runner),
117 default_file_task_runner_(file_task_runner),
118 quota_manager_proxy_(quota_manager_proxy),
119 sandbox_delegate_(new SandboxFileSystemBackendDelegate(
123 special_storage_policy,
125 sandbox_backend_(new SandboxFileSystemBackend(
126 sandbox_delegate_.get())),
127 isolated_backend_(new IsolatedFileSystemBackend()),
128 plugin_private_backend_(new PluginPrivateFileSystemBackend(
131 special_storage_policy,
133 additional_backends_(additional_backends.Pass()),
134 external_mount_points_(external_mount_points),
135 partition_path_(partition_path),
136 is_incognito_(options.is_incognito()),
137 operation_runner_(new FileSystemOperationRunner(this)) {
138 RegisterBackend(sandbox_backend_.get());
139 RegisterBackend(isolated_backend_.get());
140 RegisterBackend(plugin_private_backend_.get());
142 for (ScopedVector<FileSystemBackend>::const_iterator iter =
143 additional_backends_.begin();
144 iter != additional_backends_.end(); ++iter) {
145 RegisterBackend(*iter);
148 if (quota_manager_proxy) {
149 // Quota client assumes all backends have registered.
150 quota_manager_proxy->RegisterClient(CreateQuotaClient(
151 this, options.is_incognito()));
154 sandbox_backend_->Initialize(this);
155 isolated_backend_->Initialize(this);
156 plugin_private_backend_->Initialize(this);
157 for (ScopedVector<FileSystemBackend>::const_iterator iter =
158 additional_backends_.begin();
159 iter != additional_backends_.end(); ++iter) {
160 (*iter)->Initialize(this);
163 // Additional mount points must be added before regular system-wide
165 if (external_mount_points)
166 url_crackers_.push_back(external_mount_points);
167 url_crackers_.push_back(ExternalMountPoints::GetSystemInstance());
168 url_crackers_.push_back(IsolatedContext::GetInstance());
171 bool FileSystemContext::DeleteDataForOriginOnFileThread(
172 const GURL& origin_url) {
173 DCHECK(default_file_task_runner()->RunsTasksOnCurrentThread());
174 DCHECK(origin_url == origin_url.GetOrigin());
177 for (FileSystemBackendMap::iterator iter = backend_map_.begin();
178 iter != backend_map_.end();
180 FileSystemBackend* backend = iter->second;
181 if (!backend->GetQuotaUtil())
183 if (backend->GetQuotaUtil()->DeleteOriginDataOnFileThread(
184 this, quota_manager_proxy(), origin_url, iter->first)
185 != base::PLATFORM_FILE_OK) {
186 // Continue the loop, but record the failure.
194 void FileSystemContext::Shutdown() {
195 if (!io_task_runner_->RunsTasksOnCurrentThread()) {
196 io_task_runner_->PostTask(
197 FROM_HERE, base::Bind(&FileSystemContext::Shutdown,
198 make_scoped_refptr(this)));
201 operation_runner_->Shutdown();
205 FileSystemContext::GetQuotaUtil(FileSystemType type) const {
206 FileSystemBackend* backend = GetFileSystemBackend(type);
209 return backend->GetQuotaUtil();
212 AsyncFileUtil* FileSystemContext::GetAsyncFileUtil(
213 FileSystemType type) const {
214 FileSystemBackend* backend = GetFileSystemBackend(type);
217 return backend->GetAsyncFileUtil(type);
220 CopyOrMoveFileValidatorFactory*
221 FileSystemContext::GetCopyOrMoveFileValidatorFactory(
222 FileSystemType type, base::PlatformFileError* error_code) const {
224 *error_code = base::PLATFORM_FILE_OK;
225 FileSystemBackend* backend = GetFileSystemBackend(type);
228 return backend->GetCopyOrMoveFileValidatorFactory(
232 FileSystemBackend* FileSystemContext::GetFileSystemBackend(
233 FileSystemType type) const {
234 FileSystemBackendMap::const_iterator found = backend_map_.find(type);
235 if (found != backend_map_.end())
236 return found->second;
237 NOTREACHED() << "Unknown filesystem type: " << type;
241 bool FileSystemContext::IsSandboxFileSystem(FileSystemType type) const {
242 FileSystemBackendMap::const_iterator found = backend_map_.find(type);
243 return found != backend_map_.end() && found->second->GetQuotaUtil();
246 const UpdateObserverList* FileSystemContext::GetUpdateObservers(
247 FileSystemType type) const {
248 FileSystemBackend* backend = GetFileSystemBackend(type);
249 if (backend->GetQuotaUtil())
250 return backend->GetQuotaUtil()->GetUpdateObservers(type);
254 const AccessObserverList* FileSystemContext::GetAccessObservers(
255 FileSystemType type) const {
256 FileSystemBackend* backend = GetFileSystemBackend(type);
257 if (backend->GetQuotaUtil())
258 return backend->GetQuotaUtil()->GetAccessObservers(type);
262 void FileSystemContext::GetFileSystemTypes(
263 std::vector<FileSystemType>* types) const {
265 for (FileSystemBackendMap::const_iterator iter = backend_map_.begin();
266 iter != backend_map_.end(); ++iter)
267 types->push_back(iter->first);
270 ExternalFileSystemBackend*
271 FileSystemContext::external_backend() const {
272 return static_cast<ExternalFileSystemBackend*>(
273 GetFileSystemBackend(kFileSystemTypeExternal));
276 void FileSystemContext::OpenFileSystem(
277 const GURL& origin_url,
279 OpenFileSystemMode mode,
280 const OpenFileSystemCallback& callback) {
281 DCHECK(io_task_runner_->RunsTasksOnCurrentThread());
282 DCHECK(!callback.is_null());
284 if (!FileSystemContext::IsSandboxFileSystem(type)) {
285 // Disallow opening a non-sandboxed filesystem.
286 callback.Run(GURL(), std::string(), base::PLATFORM_FILE_ERROR_SECURITY);
290 FileSystemBackend* backend = GetFileSystemBackend(type);
292 callback.Run(GURL(), std::string(), base::PLATFORM_FILE_ERROR_SECURITY);
296 backend->OpenFileSystem(origin_url, type, mode, callback);
299 void FileSystemContext::ResolveURL(
300 const FileSystemURL& url,
301 const ResolveURLCallback& callback) {
302 DCHECK(io_task_runner_->RunsTasksOnCurrentThread());
303 DCHECK(!callback.is_null());
305 if (!FileSystemContext::IsSandboxFileSystem(url.type())) {
307 // Do not have to open a non-sandboxed filesystem.
308 // TODO(nhiroki): For now we assume this path is called only on ChromeOS,
309 // but this assumption may be broken in the future and we should handle
310 // more generally. http://crbug.com/304062.
311 FileSystemInfo info = GetFileSystemInfoForChromeOS(url.origin());
312 DidOpenFileSystemForResolveURL(
313 url, callback, info.root_url, info.name, base::PLATFORM_FILE_OK);
316 callback.Run(base::PLATFORM_FILE_ERROR_SECURITY,
317 FileSystemInfo(), base::FilePath(), false);
321 FileSystemBackend* backend = GetFileSystemBackend(url.type());
323 callback.Run(base::PLATFORM_FILE_ERROR_SECURITY,
324 FileSystemInfo(), base::FilePath(), false);
328 backend->OpenFileSystem(
329 url.origin(), url.type(),
330 OPEN_FILE_SYSTEM_FAIL_IF_NONEXISTENT,
331 base::Bind(&FileSystemContext::DidOpenFileSystemForResolveURL,
332 this, url, callback));
335 void FileSystemContext::DeleteFileSystem(
336 const GURL& origin_url,
338 const DeleteFileSystemCallback& callback) {
339 DCHECK(io_task_runner_->RunsTasksOnCurrentThread());
340 DCHECK(origin_url == origin_url.GetOrigin());
341 DCHECK(!callback.is_null());
343 FileSystemBackend* backend = GetFileSystemBackend(type);
345 callback.Run(base::PLATFORM_FILE_ERROR_SECURITY);
348 if (!backend->GetQuotaUtil()) {
349 callback.Run(base::PLATFORM_FILE_ERROR_INVALID_OPERATION);
353 base::PostTaskAndReplyWithResult(
354 default_file_task_runner(),
356 // It is safe to pass Unretained(quota_util) since context owns it.
357 base::Bind(&FileSystemQuotaUtil::DeleteOriginDataOnFileThread,
358 base::Unretained(backend->GetQuotaUtil()),
359 make_scoped_refptr(this),
360 base::Unretained(quota_manager_proxy()),
366 scoped_ptr<webkit_blob::FileStreamReader>
367 FileSystemContext::CreateFileStreamReader(
368 const FileSystemURL& url,
370 const base::Time& expected_modification_time) {
372 return scoped_ptr<webkit_blob::FileStreamReader>();
373 FileSystemBackend* backend = GetFileSystemBackend(url.type());
375 return scoped_ptr<webkit_blob::FileStreamReader>();
376 return backend->CreateFileStreamReader(
377 url, offset, expected_modification_time, this);
380 scoped_ptr<FileStreamWriter> FileSystemContext::CreateFileStreamWriter(
381 const FileSystemURL& url,
384 return scoped_ptr<FileStreamWriter>();
385 FileSystemBackend* backend = GetFileSystemBackend(url.type());
387 return scoped_ptr<FileStreamWriter>();
388 return backend->CreateFileStreamWriter(url, offset, this);
391 scoped_ptr<FileSystemOperationRunner>
392 FileSystemContext::CreateFileSystemOperationRunner() {
393 return make_scoped_ptr(new FileSystemOperationRunner(this));
396 FileSystemURL FileSystemContext::CrackURL(const GURL& url) const {
397 return CrackFileSystemURL(FileSystemURL(url));
400 FileSystemURL FileSystemContext::CreateCrackedFileSystemURL(
403 const base::FilePath& path) const {
404 return CrackFileSystemURL(FileSystemURL(origin, type, path));
407 #if defined(OS_CHROMEOS) && defined(GOOGLE_CHROME_BUILD)
408 void FileSystemContext::EnableTemporaryFileSystemInIncognito() {
409 sandbox_backend_->set_enable_temporary_file_system_in_incognito(true);
413 bool FileSystemContext::CanServeURLRequest(const FileSystemURL& url) const {
414 // We never support accessing files in isolated filesystems via an URL.
415 if (url.mount_type() == kFileSystemTypeIsolated)
417 #if defined(OS_CHROMEOS) && defined(GOOGLE_CHROME_BUILD)
418 if (url.type() == kFileSystemTypeTemporary &&
419 sandbox_backend_->enable_temporary_file_system_in_incognito()) {
423 return !is_incognito_ || !FileSystemContext::IsSandboxFileSystem(url.type());
426 void FileSystemContext::OpenPluginPrivateFileSystem(
427 const GURL& origin_url,
429 const std::string& plugin_id,
430 OpenFileSystemMode mode,
431 const OpenPluginPrivateFileSystemCallback& callback) {
432 DCHECK(plugin_private_backend_);
433 plugin_private_backend_->OpenPrivateFileSystem(
434 origin_url, type, plugin_id, mode, callback);
437 FileSystemContext::~FileSystemContext() {
440 void FileSystemContext::DeleteOnCorrectThread() const {
441 if (!io_task_runner_->RunsTasksOnCurrentThread() &&
442 io_task_runner_->DeleteSoon(FROM_HERE, this)) {
448 FileSystemOperation* FileSystemContext::CreateFileSystemOperation(
449 const FileSystemURL& url, base::PlatformFileError* error_code) {
450 if (!url.is_valid()) {
452 *error_code = base::PLATFORM_FILE_ERROR_INVALID_URL;
456 FileSystemBackend* backend = GetFileSystemBackend(url.type());
459 *error_code = base::PLATFORM_FILE_ERROR_FAILED;
463 base::PlatformFileError fs_error = base::PLATFORM_FILE_OK;
464 FileSystemOperation* operation =
465 backend->CreateFileSystemOperation(url, this, &fs_error);
468 *error_code = fs_error;
472 FileSystemURL FileSystemContext::CrackFileSystemURL(
473 const FileSystemURL& url) const {
475 return FileSystemURL();
477 // The returned value in case there is no crackers which can crack the url.
478 // This is valid situation for non isolated/external file systems.
479 FileSystemURL current = url;
481 // File system may be mounted multiple times (e.g., an isolated filesystem on
482 // top of an external filesystem). Hence cracking needs to be iterated.
484 FileSystemURL cracked = current;
485 for (size_t i = 0; i < url_crackers_.size(); ++i) {
486 if (!url_crackers_[i]->HandlesFileSystemMountType(current.type()))
488 cracked = url_crackers_[i]->CrackFileSystemURL(current);
489 if (cracked.is_valid())
492 if (cracked == current)
499 void FileSystemContext::RegisterBackend(FileSystemBackend* backend) {
500 const FileSystemType mount_types[] = {
501 kFileSystemTypeTemporary,
502 kFileSystemTypePersistent,
503 kFileSystemTypeIsolated,
504 kFileSystemTypeExternal,
506 // Register file system backends for public mount types.
507 for (size_t j = 0; j < ARRAYSIZE_UNSAFE(mount_types); ++j) {
508 if (backend->CanHandleType(mount_types[j])) {
509 const bool inserted = backend_map_.insert(
510 std::make_pair(mount_types[j], backend)).second;
514 // Register file system backends for internal types.
515 for (int t = kFileSystemInternalTypeEnumStart + 1;
516 t < kFileSystemInternalTypeEnumEnd; ++t) {
517 FileSystemType type = static_cast<FileSystemType>(t);
518 if (backend->CanHandleType(type)) {
519 const bool inserted = backend_map_.insert(
520 std::make_pair(type, backend)).second;
526 void FileSystemContext::DidOpenFileSystemForResolveURL(
527 const FileSystemURL& url,
528 const FileSystemContext::ResolveURLCallback& callback,
529 const GURL& filesystem_root,
530 const std::string& filesystem_name,
531 base::PlatformFileError error) {
532 DCHECK(io_task_runner_->RunsTasksOnCurrentThread());
534 if (error != base::PLATFORM_FILE_OK) {
535 callback.Run(error, FileSystemInfo(), base::FilePath(), false);
539 fileapi::FileSystemInfo info(
540 filesystem_name, filesystem_root, url.mount_type());
542 // Extract the virtual path not containing a filesystem type part from |url|.
543 base::FilePath parent = CrackURL(filesystem_root).virtual_path();
544 base::FilePath child = url.virtual_path();
547 if (parent.empty()) {
549 } else if (parent != child) {
550 bool result = parent.AppendRelativePath(child, &path);
554 operation_runner()->GetMetadata(
555 url, base::Bind(&DidGetMetadataForResolveURL, path, callback, info));
558 } // namespace fileapi