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/quota/quota_reservation.h"
27 #include "webkit/browser/fileapi/sandbox_file_system_backend.h"
28 #include "webkit/browser/quota/quota_manager_proxy.h"
29 #include "webkit/browser/quota/special_storage_policy.h"
30 #include "webkit/common/fileapi/file_system_info.h"
31 #include "webkit/common/fileapi/file_system_util.h"
33 using quota::QuotaClient;
39 QuotaClient* CreateQuotaClient(
40 FileSystemContext* context,
42 return new FileSystemQuotaClient(context, is_incognito);
46 void DidGetMetadataForResolveURL(
47 const base::FilePath& path,
48 const FileSystemContext::ResolveURLCallback& callback,
49 const FileSystemInfo& info,
50 base::File::Error error,
51 const base::File::Info& file_info) {
52 if (error != base::File::FILE_OK) {
53 callback.Run(error, FileSystemInfo(), base::FilePath(), false);
56 callback.Run(error, info, path, file_info.is_directory);
62 int FileSystemContext::GetPermissionPolicy(FileSystemType type) {
64 case kFileSystemTypeTemporary:
65 case kFileSystemTypePersistent:
66 case kFileSystemTypeSyncable:
67 return FILE_PERMISSION_SANDBOX;
69 case kFileSystemTypeDrive:
70 case kFileSystemTypeNativeForPlatformApp:
71 case kFileSystemTypeNativeLocal:
72 case kFileSystemTypeCloudDevice:
73 return FILE_PERMISSION_USE_FILE_PERMISSION;
75 case kFileSystemTypeRestrictedNativeLocal:
76 return FILE_PERMISSION_READ_ONLY |
77 FILE_PERMISSION_USE_FILE_PERMISSION;
79 // Following types are only accessed via IsolatedFileSystem, and
80 // don't have their own permission policies.
81 case kFileSystemTypeDeviceMedia:
82 case kFileSystemTypeDragged:
83 case kFileSystemTypeForTransientFile:
84 case kFileSystemTypeIphoto:
85 case kFileSystemTypeItunes:
86 case kFileSystemTypeNativeMedia:
87 case kFileSystemTypePicasa:
88 case kFileSystemTypePluginPrivate:
89 return FILE_PERMISSION_ALWAYS_DENY;
91 // Following types only appear as mount_type, and will not be
92 // queried for their permission policies.
93 case kFileSystemTypeIsolated:
94 case kFileSystemTypeExternal:
95 return FILE_PERMISSION_ALWAYS_DENY;
97 // Following types should not be used to access files by FileAPI clients.
98 case kFileSystemTypeTest:
99 case kFileSystemTypeSyncableForInternalSync:
100 case kFileSystemInternalTypeEnumEnd:
101 case kFileSystemInternalTypeEnumStart:
102 case kFileSystemTypeUnknown:
103 return FILE_PERMISSION_ALWAYS_DENY;
106 return FILE_PERMISSION_ALWAYS_DENY;
109 FileSystemContext::FileSystemContext(
110 base::SingleThreadTaskRunner* io_task_runner,
111 base::SequencedTaskRunner* file_task_runner,
112 ExternalMountPoints* external_mount_points,
113 quota::SpecialStoragePolicy* special_storage_policy,
114 quota::QuotaManagerProxy* quota_manager_proxy,
115 ScopedVector<FileSystemBackend> additional_backends,
116 const base::FilePath& partition_path,
117 const FileSystemOptions& options)
118 : io_task_runner_(io_task_runner),
119 default_file_task_runner_(file_task_runner),
120 quota_manager_proxy_(quota_manager_proxy),
121 sandbox_delegate_(new SandboxFileSystemBackendDelegate(
125 special_storage_policy,
127 sandbox_backend_(new SandboxFileSystemBackend(
128 sandbox_delegate_.get())),
129 isolated_backend_(new IsolatedFileSystemBackend()),
130 plugin_private_backend_(new PluginPrivateFileSystemBackend(
133 special_storage_policy,
135 additional_backends_(additional_backends.Pass()),
136 external_mount_points_(external_mount_points),
137 partition_path_(partition_path),
138 is_incognito_(options.is_incognito()),
139 operation_runner_(new FileSystemOperationRunner(this)) {
140 RegisterBackend(sandbox_backend_.get());
141 RegisterBackend(isolated_backend_.get());
142 RegisterBackend(plugin_private_backend_.get());
144 for (ScopedVector<FileSystemBackend>::const_iterator iter =
145 additional_backends_.begin();
146 iter != additional_backends_.end(); ++iter) {
147 RegisterBackend(*iter);
150 if (quota_manager_proxy) {
151 // Quota client assumes all backends have registered.
152 quota_manager_proxy->RegisterClient(CreateQuotaClient(
153 this, options.is_incognito()));
156 sandbox_backend_->Initialize(this);
157 isolated_backend_->Initialize(this);
158 plugin_private_backend_->Initialize(this);
159 for (ScopedVector<FileSystemBackend>::const_iterator iter =
160 additional_backends_.begin();
161 iter != additional_backends_.end(); ++iter) {
162 (*iter)->Initialize(this);
165 // Additional mount points must be added before regular system-wide
167 if (external_mount_points)
168 url_crackers_.push_back(external_mount_points);
169 url_crackers_.push_back(ExternalMountPoints::GetSystemInstance());
170 url_crackers_.push_back(IsolatedContext::GetInstance());
173 bool FileSystemContext::DeleteDataForOriginOnFileTaskRunner(
174 const GURL& origin_url) {
175 DCHECK(default_file_task_runner()->RunsTasksOnCurrentThread());
176 DCHECK(origin_url == origin_url.GetOrigin());
179 for (FileSystemBackendMap::iterator iter = backend_map_.begin();
180 iter != backend_map_.end();
182 FileSystemBackend* backend = iter->second;
183 if (!backend->GetQuotaUtil())
185 if (backend->GetQuotaUtil()->DeleteOriginDataOnFileTaskRunner(
186 this, quota_manager_proxy(), origin_url, iter->first)
187 != base::File::FILE_OK) {
188 // Continue the loop, but record the failure.
196 scoped_refptr<QuotaReservation>
197 FileSystemContext::CreateQuotaReservationOnFileTaskRunner(
198 const GURL& origin_url,
199 FileSystemType type) {
200 DCHECK(default_file_task_runner()->RunsTasksOnCurrentThread());
201 FileSystemBackend* backend = GetFileSystemBackend(type);
202 if (!backend || !backend->GetQuotaUtil())
203 return scoped_refptr<QuotaReservation>();
204 return backend->GetQuotaUtil()->CreateQuotaReservationOnFileTaskRunner(
208 void FileSystemContext::Shutdown() {
209 if (!io_task_runner_->RunsTasksOnCurrentThread()) {
210 io_task_runner_->PostTask(
211 FROM_HERE, base::Bind(&FileSystemContext::Shutdown,
212 make_scoped_refptr(this)));
215 operation_runner_->Shutdown();
219 FileSystemContext::GetQuotaUtil(FileSystemType type) const {
220 FileSystemBackend* backend = GetFileSystemBackend(type);
223 return backend->GetQuotaUtil();
226 AsyncFileUtil* FileSystemContext::GetAsyncFileUtil(
227 FileSystemType type) const {
228 FileSystemBackend* backend = GetFileSystemBackend(type);
231 return backend->GetAsyncFileUtil(type);
234 CopyOrMoveFileValidatorFactory*
235 FileSystemContext::GetCopyOrMoveFileValidatorFactory(
236 FileSystemType type, base::File::Error* error_code) const {
238 *error_code = base::File::FILE_OK;
239 FileSystemBackend* backend = GetFileSystemBackend(type);
242 return backend->GetCopyOrMoveFileValidatorFactory(
246 FileSystemBackend* FileSystemContext::GetFileSystemBackend(
247 FileSystemType type) const {
248 FileSystemBackendMap::const_iterator found = backend_map_.find(type);
249 if (found != backend_map_.end())
250 return found->second;
251 NOTREACHED() << "Unknown filesystem type: " << type;
255 bool FileSystemContext::IsSandboxFileSystem(FileSystemType type) const {
256 FileSystemBackendMap::const_iterator found = backend_map_.find(type);
257 return found != backend_map_.end() && found->second->GetQuotaUtil();
260 const UpdateObserverList* FileSystemContext::GetUpdateObservers(
261 FileSystemType type) const {
262 FileSystemBackend* backend = GetFileSystemBackend(type);
263 if (backend->GetQuotaUtil())
264 return backend->GetQuotaUtil()->GetUpdateObservers(type);
268 const AccessObserverList* FileSystemContext::GetAccessObservers(
269 FileSystemType type) const {
270 FileSystemBackend* backend = GetFileSystemBackend(type);
271 if (backend->GetQuotaUtil())
272 return backend->GetQuotaUtil()->GetAccessObservers(type);
276 void FileSystemContext::GetFileSystemTypes(
277 std::vector<FileSystemType>* types) const {
279 for (FileSystemBackendMap::const_iterator iter = backend_map_.begin();
280 iter != backend_map_.end(); ++iter)
281 types->push_back(iter->first);
284 ExternalFileSystemBackend*
285 FileSystemContext::external_backend() const {
286 return static_cast<ExternalFileSystemBackend*>(
287 GetFileSystemBackend(kFileSystemTypeExternal));
290 void FileSystemContext::OpenFileSystem(
291 const GURL& origin_url,
293 OpenFileSystemMode mode,
294 const OpenFileSystemCallback& callback) {
295 DCHECK(io_task_runner_->RunsTasksOnCurrentThread());
296 DCHECK(!callback.is_null());
298 if (!FileSystemContext::IsSandboxFileSystem(type)) {
299 // Disallow opening a non-sandboxed filesystem.
300 callback.Run(GURL(), std::string(), base::File::FILE_ERROR_SECURITY);
304 FileSystemBackend* backend = GetFileSystemBackend(type);
306 callback.Run(GURL(), std::string(), base::File::FILE_ERROR_SECURITY);
310 backend->OpenFileSystem(origin_url, type, mode, callback);
313 void FileSystemContext::ResolveURL(
314 const FileSystemURL& url,
315 const ResolveURLCallback& callback) {
316 DCHECK(io_task_runner_->RunsTasksOnCurrentThread());
317 DCHECK(!callback.is_null());
319 if (!FileSystemContext::IsSandboxFileSystem(url.type())) {
321 // Do not have to open a non-sandboxed filesystem.
322 // TODO(nhiroki): For now we assume this path is called only on ChromeOS,
323 // but this assumption may be broken in the future and we should handle
324 // more generally. http://crbug.com/304062.
325 FileSystemInfo info = GetFileSystemInfoForChromeOS(url.origin());
326 DidOpenFileSystemForResolveURL(
327 url, callback, info.root_url, info.name, base::File::FILE_OK);
330 callback.Run(base::File::FILE_ERROR_SECURITY,
331 FileSystemInfo(), base::FilePath(), false);
335 FileSystemBackend* backend = GetFileSystemBackend(url.type());
337 callback.Run(base::File::FILE_ERROR_SECURITY,
338 FileSystemInfo(), base::FilePath(), false);
342 backend->OpenFileSystem(
343 url.origin(), url.type(),
344 OPEN_FILE_SYSTEM_FAIL_IF_NONEXISTENT,
345 base::Bind(&FileSystemContext::DidOpenFileSystemForResolveURL,
346 this, url, callback));
349 void FileSystemContext::DeleteFileSystem(
350 const GURL& origin_url,
352 const StatusCallback& callback) {
353 DCHECK(io_task_runner_->RunsTasksOnCurrentThread());
354 DCHECK(origin_url == origin_url.GetOrigin());
355 DCHECK(!callback.is_null());
357 FileSystemBackend* backend = GetFileSystemBackend(type);
359 callback.Run(base::File::FILE_ERROR_SECURITY);
362 if (!backend->GetQuotaUtil()) {
363 callback.Run(base::File::FILE_ERROR_INVALID_OPERATION);
367 base::PostTaskAndReplyWithResult(
368 default_file_task_runner(),
370 // It is safe to pass Unretained(quota_util) since context owns it.
371 base::Bind(&FileSystemQuotaUtil::DeleteOriginDataOnFileTaskRunner,
372 base::Unretained(backend->GetQuotaUtil()),
373 make_scoped_refptr(this),
374 base::Unretained(quota_manager_proxy()),
380 scoped_ptr<webkit_blob::FileStreamReader>
381 FileSystemContext::CreateFileStreamReader(
382 const FileSystemURL& url,
384 const base::Time& expected_modification_time) {
386 return scoped_ptr<webkit_blob::FileStreamReader>();
387 FileSystemBackend* backend = GetFileSystemBackend(url.type());
389 return scoped_ptr<webkit_blob::FileStreamReader>();
390 return backend->CreateFileStreamReader(
391 url, offset, expected_modification_time, this);
394 scoped_ptr<FileStreamWriter> FileSystemContext::CreateFileStreamWriter(
395 const FileSystemURL& url,
398 return scoped_ptr<FileStreamWriter>();
399 FileSystemBackend* backend = GetFileSystemBackend(url.type());
401 return scoped_ptr<FileStreamWriter>();
402 return backend->CreateFileStreamWriter(url, offset, this);
405 scoped_ptr<FileSystemOperationRunner>
406 FileSystemContext::CreateFileSystemOperationRunner() {
407 return make_scoped_ptr(new FileSystemOperationRunner(this));
410 FileSystemURL FileSystemContext::CrackURL(const GURL& url) const {
411 return CrackFileSystemURL(FileSystemURL(url));
414 FileSystemURL FileSystemContext::CreateCrackedFileSystemURL(
417 const base::FilePath& path) const {
418 return CrackFileSystemURL(FileSystemURL(origin, type, path));
421 #if defined(OS_CHROMEOS)
422 void FileSystemContext::EnableTemporaryFileSystemInIncognito() {
423 sandbox_backend_->set_enable_temporary_file_system_in_incognito(true);
427 bool FileSystemContext::CanServeURLRequest(const FileSystemURL& url) const {
428 // We never support accessing files in isolated filesystems via an URL.
429 if (url.mount_type() == kFileSystemTypeIsolated)
431 #if defined(OS_CHROMEOS)
432 if (url.type() == kFileSystemTypeTemporary &&
433 sandbox_backend_->enable_temporary_file_system_in_incognito()) {
437 return !is_incognito_ || !FileSystemContext::IsSandboxFileSystem(url.type());
440 void FileSystemContext::OpenPluginPrivateFileSystem(
441 const GURL& origin_url,
443 const std::string& filesystem_id,
444 const std::string& plugin_id,
445 OpenFileSystemMode mode,
446 const StatusCallback& callback) {
447 DCHECK(plugin_private_backend_);
448 plugin_private_backend_->OpenPrivateFileSystem(
449 origin_url, type, filesystem_id, plugin_id, mode, callback);
452 FileSystemContext::~FileSystemContext() {
455 void FileSystemContext::DeleteOnCorrectThread() const {
456 if (!io_task_runner_->RunsTasksOnCurrentThread() &&
457 io_task_runner_->DeleteSoon(FROM_HERE, this)) {
463 FileSystemOperation* FileSystemContext::CreateFileSystemOperation(
464 const FileSystemURL& url, base::File::Error* error_code) {
465 if (!url.is_valid()) {
467 *error_code = base::File::FILE_ERROR_INVALID_URL;
471 FileSystemBackend* backend = GetFileSystemBackend(url.type());
474 *error_code = base::File::FILE_ERROR_FAILED;
478 base::File::Error fs_error = base::File::FILE_OK;
479 FileSystemOperation* operation =
480 backend->CreateFileSystemOperation(url, this, &fs_error);
483 *error_code = fs_error;
487 FileSystemURL FileSystemContext::CrackFileSystemURL(
488 const FileSystemURL& url) const {
490 return FileSystemURL();
492 // The returned value in case there is no crackers which can crack the url.
493 // This is valid situation for non isolated/external file systems.
494 FileSystemURL current = url;
496 // File system may be mounted multiple times (e.g., an isolated filesystem on
497 // top of an external filesystem). Hence cracking needs to be iterated.
499 FileSystemURL cracked = current;
500 for (size_t i = 0; i < url_crackers_.size(); ++i) {
501 if (!url_crackers_[i]->HandlesFileSystemMountType(current.type()))
503 cracked = url_crackers_[i]->CrackFileSystemURL(current);
504 if (cracked.is_valid())
507 if (cracked == current)
514 void FileSystemContext::RegisterBackend(FileSystemBackend* backend) {
515 const FileSystemType mount_types[] = {
516 kFileSystemTypeTemporary,
517 kFileSystemTypePersistent,
518 kFileSystemTypeIsolated,
519 kFileSystemTypeExternal,
521 // Register file system backends for public mount types.
522 for (size_t j = 0; j < ARRAYSIZE_UNSAFE(mount_types); ++j) {
523 if (backend->CanHandleType(mount_types[j])) {
524 const bool inserted = backend_map_.insert(
525 std::make_pair(mount_types[j], backend)).second;
529 // Register file system backends for internal types.
530 for (int t = kFileSystemInternalTypeEnumStart + 1;
531 t < kFileSystemInternalTypeEnumEnd; ++t) {
532 FileSystemType type = static_cast<FileSystemType>(t);
533 if (backend->CanHandleType(type)) {
534 const bool inserted = backend_map_.insert(
535 std::make_pair(type, backend)).second;
541 void FileSystemContext::DidOpenFileSystemForResolveURL(
542 const FileSystemURL& url,
543 const FileSystemContext::ResolveURLCallback& callback,
544 const GURL& filesystem_root,
545 const std::string& filesystem_name,
546 base::File::Error error) {
547 DCHECK(io_task_runner_->RunsTasksOnCurrentThread());
549 if (error != base::File::FILE_OK) {
550 callback.Run(error, FileSystemInfo(), base::FilePath(), false);
554 fileapi::FileSystemInfo info(
555 filesystem_name, filesystem_root, url.mount_type());
557 // Extract the virtual path not containing a filesystem type part from |url|.
558 base::FilePath parent = CrackURL(filesystem_root).virtual_path();
559 base::FilePath child = url.virtual_path();
562 if (parent.empty()) {
564 } else if (parent != child) {
565 bool result = parent.AppendRelativePath(child, &path);
569 operation_runner()->GetMetadata(
570 url, base::Bind(&DidGetMetadataForResolveURL, path, callback, info));
573 } // namespace fileapi