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 "storage/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"
11 #include "base/thread_task_runner_handle.h"
12 #include "net/url_request/url_request.h"
13 #include "storage/browser/fileapi/copy_or_move_file_validator.h"
14 #include "storage/browser/fileapi/external_mount_points.h"
15 #include "storage/browser/fileapi/file_permission_policy.h"
16 #include "storage/browser/fileapi/file_stream_reader.h"
17 #include "storage/browser/fileapi/file_stream_writer.h"
18 #include "storage/browser/fileapi/file_system_file_util.h"
19 #include "storage/browser/fileapi/file_system_operation.h"
20 #include "storage/browser/fileapi/file_system_operation_runner.h"
21 #include "storage/browser/fileapi/file_system_options.h"
22 #include "storage/browser/fileapi/file_system_quota_client.h"
23 #include "storage/browser/fileapi/isolated_context.h"
24 #include "storage/browser/fileapi/isolated_file_system_backend.h"
25 #include "storage/browser/fileapi/mount_points.h"
26 #include "storage/browser/fileapi/quota/quota_reservation.h"
27 #include "storage/browser/fileapi/sandbox_file_system_backend.h"
28 #include "storage/browser/quota/quota_manager_proxy.h"
29 #include "storage/browser/quota/special_storage_policy.h"
30 #include "storage/common/fileapi/file_system_info.h"
31 #include "storage/common/fileapi/file_system_util.h"
34 using storage::QuotaClient
;
40 QuotaClient
* CreateQuotaClient(
41 FileSystemContext
* context
,
43 return new FileSystemQuotaClient(context
, is_incognito
);
47 void DidGetMetadataForResolveURL(
48 const base::FilePath
& path
,
49 const FileSystemContext::ResolveURLCallback
& callback
,
50 const FileSystemInfo
& info
,
51 base::File::Error error
,
52 const base::File::Info
& file_info
) {
53 if (error
!= base::File::FILE_OK
) {
54 if (error
== base::File::FILE_ERROR_NOT_FOUND
) {
55 callback
.Run(base::File::FILE_OK
, info
, path
,
56 FileSystemContext::RESOLVED_ENTRY_NOT_FOUND
);
58 callback
.Run(error
, FileSystemInfo(), base::FilePath(),
59 FileSystemContext::RESOLVED_ENTRY_NOT_FOUND
);
63 callback
.Run(error
, info
, path
, file_info
.is_directory
?
64 FileSystemContext::RESOLVED_ENTRY_DIRECTORY
:
65 FileSystemContext::RESOLVED_ENTRY_FILE
);
68 void RelayResolveURLCallback(
69 scoped_refptr
<base::SingleThreadTaskRunner
> task_runner
,
70 const FileSystemContext::ResolveURLCallback
& callback
,
71 base::File::Error result
,
72 const FileSystemInfo
& info
,
73 const base::FilePath
& file_path
,
74 FileSystemContext::ResolvedEntryType type
) {
75 task_runner
->PostTask(
76 FROM_HERE
, base::Bind(callback
, result
, info
, file_path
, type
));
82 int FileSystemContext::GetPermissionPolicy(FileSystemType type
) {
84 case kFileSystemTypeTemporary
:
85 case kFileSystemTypePersistent
:
86 case kFileSystemTypeSyncable
:
87 return FILE_PERMISSION_SANDBOX
;
89 case kFileSystemTypeDrive
:
90 case kFileSystemTypeNativeForPlatformApp
:
91 case kFileSystemTypeNativeLocal
:
92 case kFileSystemTypeCloudDevice
:
93 case kFileSystemTypeProvided
:
94 case kFileSystemTypeDeviceMediaAsFileStorage
:
95 return FILE_PERMISSION_USE_FILE_PERMISSION
;
97 case kFileSystemTypeRestrictedNativeLocal
:
98 return FILE_PERMISSION_READ_ONLY
|
99 FILE_PERMISSION_USE_FILE_PERMISSION
;
101 case kFileSystemTypeDeviceMedia
:
102 case kFileSystemTypeIphoto
:
103 case kFileSystemTypeItunes
:
104 case kFileSystemTypeNativeMedia
:
105 case kFileSystemTypePicasa
:
106 return FILE_PERMISSION_USE_FILE_PERMISSION
;
108 // Following types are only accessed via IsolatedFileSystem, and
109 // don't have their own permission policies.
110 case kFileSystemTypeDragged
:
111 case kFileSystemTypeForTransientFile
:
112 case kFileSystemTypePluginPrivate
:
113 return FILE_PERMISSION_ALWAYS_DENY
;
115 // Following types only appear as mount_type, and will not be
116 // queried for their permission policies.
117 case kFileSystemTypeIsolated
:
118 case kFileSystemTypeExternal
:
119 return FILE_PERMISSION_ALWAYS_DENY
;
121 // Following types should not be used to access files by FileAPI clients.
122 case kFileSystemTypeTest
:
123 case kFileSystemTypeSyncableForInternalSync
:
124 case kFileSystemInternalTypeEnumEnd
:
125 case kFileSystemInternalTypeEnumStart
:
126 case kFileSystemTypeUnknown
:
127 return FILE_PERMISSION_ALWAYS_DENY
;
130 return FILE_PERMISSION_ALWAYS_DENY
;
133 FileSystemContext::FileSystemContext(
134 base::SingleThreadTaskRunner
* io_task_runner
,
135 base::SequencedTaskRunner
* file_task_runner
,
136 ExternalMountPoints
* external_mount_points
,
137 storage::SpecialStoragePolicy
* special_storage_policy
,
138 storage::QuotaManagerProxy
* quota_manager_proxy
,
139 ScopedVector
<FileSystemBackend
> additional_backends
,
140 const std::vector
<URLRequestAutoMountHandler
>& auto_mount_handlers
,
141 const base::FilePath
& partition_path
,
142 const FileSystemOptions
& options
)
143 : io_task_runner_(io_task_runner
),
144 default_file_task_runner_(file_task_runner
),
145 quota_manager_proxy_(quota_manager_proxy
),
147 new SandboxFileSystemBackendDelegate(quota_manager_proxy
,
150 special_storage_policy
,
152 sandbox_backend_(new SandboxFileSystemBackend(sandbox_delegate_
.get())),
153 plugin_private_backend_(
154 new PluginPrivateFileSystemBackend(file_task_runner
,
156 special_storage_policy
,
158 additional_backends_(additional_backends
.Pass()),
159 auto_mount_handlers_(auto_mount_handlers
),
160 external_mount_points_(external_mount_points
),
161 partition_path_(partition_path
),
162 is_incognito_(options
.is_incognito()),
163 operation_runner_(new FileSystemOperationRunner(this)) {
164 RegisterBackend(sandbox_backend_
.get());
165 RegisterBackend(plugin_private_backend_
.get());
167 for (ScopedVector
<FileSystemBackend
>::const_iterator iter
=
168 additional_backends_
.begin();
169 iter
!= additional_backends_
.end(); ++iter
) {
170 RegisterBackend(*iter
);
173 // If the embedder's additional backends already provide support for
174 // kFileSystemTypeNativeLocal and kFileSystemTypeNativeForPlatformApp then
175 // IsolatedFileSystemBackend does not need to handle them. For example, on
176 // Chrome OS the additional backend chromeos::FileSystemBackend handles these
178 isolated_backend_
.reset(new IsolatedFileSystemBackend(
179 !ContainsKey(backend_map_
, kFileSystemTypeNativeLocal
),
180 !ContainsKey(backend_map_
, kFileSystemTypeNativeForPlatformApp
)));
181 RegisterBackend(isolated_backend_
.get());
183 if (quota_manager_proxy
) {
184 // Quota client assumes all backends have registered.
185 quota_manager_proxy
->RegisterClient(CreateQuotaClient(
186 this, options
.is_incognito()));
189 sandbox_backend_
->Initialize(this);
190 isolated_backend_
->Initialize(this);
191 plugin_private_backend_
->Initialize(this);
192 for (ScopedVector
<FileSystemBackend
>::const_iterator iter
=
193 additional_backends_
.begin();
194 iter
!= additional_backends_
.end(); ++iter
) {
195 (*iter
)->Initialize(this);
198 // Additional mount points must be added before regular system-wide
200 if (external_mount_points
)
201 url_crackers_
.push_back(external_mount_points
);
202 url_crackers_
.push_back(ExternalMountPoints::GetSystemInstance());
203 url_crackers_
.push_back(IsolatedContext::GetInstance());
206 bool FileSystemContext::DeleteDataForOriginOnFileTaskRunner(
207 const GURL
& origin_url
) {
208 DCHECK(default_file_task_runner()->RunsTasksOnCurrentThread());
209 DCHECK(origin_url
== origin_url
.GetOrigin());
212 for (FileSystemBackendMap::iterator iter
= backend_map_
.begin();
213 iter
!= backend_map_
.end();
215 FileSystemBackend
* backend
= iter
->second
;
216 if (!backend
->GetQuotaUtil())
218 if (backend
->GetQuotaUtil()->DeleteOriginDataOnFileTaskRunner(
219 this, quota_manager_proxy(), origin_url
, iter
->first
)
220 != base::File::FILE_OK
) {
221 // Continue the loop, but record the failure.
229 scoped_refptr
<QuotaReservation
>
230 FileSystemContext::CreateQuotaReservationOnFileTaskRunner(
231 const GURL
& origin_url
,
232 FileSystemType type
) {
233 DCHECK(default_file_task_runner()->RunsTasksOnCurrentThread());
234 FileSystemBackend
* backend
= GetFileSystemBackend(type
);
235 if (!backend
|| !backend
->GetQuotaUtil())
236 return scoped_refptr
<QuotaReservation
>();
237 return backend
->GetQuotaUtil()->CreateQuotaReservationOnFileTaskRunner(
241 void FileSystemContext::Shutdown() {
242 if (!io_task_runner_
->RunsTasksOnCurrentThread()) {
243 io_task_runner_
->PostTask(
244 FROM_HERE
, base::Bind(&FileSystemContext::Shutdown
,
245 make_scoped_refptr(this)));
248 operation_runner_
->Shutdown();
252 FileSystemContext::GetQuotaUtil(FileSystemType type
) const {
253 FileSystemBackend
* backend
= GetFileSystemBackend(type
);
256 return backend
->GetQuotaUtil();
259 AsyncFileUtil
* FileSystemContext::GetAsyncFileUtil(
260 FileSystemType type
) const {
261 FileSystemBackend
* backend
= GetFileSystemBackend(type
);
264 return backend
->GetAsyncFileUtil(type
);
267 CopyOrMoveFileValidatorFactory
*
268 FileSystemContext::GetCopyOrMoveFileValidatorFactory(
269 FileSystemType type
, base::File::Error
* error_code
) const {
271 *error_code
= base::File::FILE_OK
;
272 FileSystemBackend
* backend
= GetFileSystemBackend(type
);
275 return backend
->GetCopyOrMoveFileValidatorFactory(
279 FileSystemBackend
* FileSystemContext::GetFileSystemBackend(
280 FileSystemType type
) const {
281 FileSystemBackendMap::const_iterator found
= backend_map_
.find(type
);
282 if (found
!= backend_map_
.end())
283 return found
->second
;
284 NOTREACHED() << "Unknown filesystem type: " << type
;
288 WatcherManager
* FileSystemContext::GetWatcherManager(
289 FileSystemType type
) const {
290 FileSystemBackend
* backend
= GetFileSystemBackend(type
);
293 return backend
->GetWatcherManager(type
);
296 bool FileSystemContext::IsSandboxFileSystem(FileSystemType type
) const {
297 FileSystemBackendMap::const_iterator found
= backend_map_
.find(type
);
298 return found
!= backend_map_
.end() && found
->second
->GetQuotaUtil();
301 const UpdateObserverList
* FileSystemContext::GetUpdateObservers(
302 FileSystemType type
) const {
303 FileSystemBackend
* backend
= GetFileSystemBackend(type
);
304 return backend
->GetUpdateObservers(type
);
307 const ChangeObserverList
* FileSystemContext::GetChangeObservers(
308 FileSystemType type
) const {
309 FileSystemBackend
* backend
= GetFileSystemBackend(type
);
310 return backend
->GetChangeObservers(type
);
313 const AccessObserverList
* FileSystemContext::GetAccessObservers(
314 FileSystemType type
) const {
315 FileSystemBackend
* backend
= GetFileSystemBackend(type
);
316 return backend
->GetAccessObservers(type
);
319 void FileSystemContext::GetFileSystemTypes(
320 std::vector
<FileSystemType
>* types
) const {
322 for (FileSystemBackendMap::const_iterator iter
= backend_map_
.begin();
323 iter
!= backend_map_
.end(); ++iter
)
324 types
->push_back(iter
->first
);
327 ExternalFileSystemBackend
*
328 FileSystemContext::external_backend() const {
329 return static_cast<ExternalFileSystemBackend
*>(
330 GetFileSystemBackend(kFileSystemTypeExternal
));
333 void FileSystemContext::OpenFileSystem(
334 const GURL
& origin_url
,
336 OpenFileSystemMode mode
,
337 const OpenFileSystemCallback
& callback
) {
338 DCHECK(io_task_runner_
->RunsTasksOnCurrentThread());
339 DCHECK(!callback
.is_null());
341 if (!FileSystemContext::IsSandboxFileSystem(type
)) {
342 // Disallow opening a non-sandboxed filesystem.
343 callback
.Run(GURL(), std::string(), base::File::FILE_ERROR_SECURITY
);
347 FileSystemBackend
* backend
= GetFileSystemBackend(type
);
349 callback
.Run(GURL(), std::string(), base::File::FILE_ERROR_SECURITY
);
354 CreateCrackedFileSystemURL(origin_url
, type
, base::FilePath()),
359 void FileSystemContext::ResolveURL(
360 const FileSystemURL
& url
,
361 const ResolveURLCallback
& callback
) {
362 DCHECK(!callback
.is_null());
364 // If not on IO thread, forward before passing the task to the backend.
365 if (!io_task_runner_
->RunsTasksOnCurrentThread()) {
366 ResolveURLCallback relay_callback
=
367 base::Bind(&RelayResolveURLCallback
,
368 base::ThreadTaskRunnerHandle::Get(), callback
);
369 io_task_runner_
->PostTask(
371 base::Bind(&FileSystemContext::ResolveURL
, this, url
, relay_callback
));
375 FileSystemBackend
* backend
= GetFileSystemBackend(url
.type());
377 callback
.Run(base::File::FILE_ERROR_SECURITY
,
378 FileSystemInfo(), base::FilePath(),
379 FileSystemContext::RESOLVED_ENTRY_NOT_FOUND
);
385 OPEN_FILE_SYSTEM_FAIL_IF_NONEXISTENT
,
386 base::Bind(&FileSystemContext::DidOpenFileSystemForResolveURL
,
392 void FileSystemContext::AttemptAutoMountForURLRequest(
393 const net::URLRequest
* url_request
,
394 const std::string
& storage_domain
,
395 const StatusCallback
& callback
) {
396 FileSystemURL
filesystem_url(url_request
->url());
397 if (filesystem_url
.type() == kFileSystemTypeExternal
) {
398 for (size_t i
= 0; i
< auto_mount_handlers_
.size(); i
++) {
399 if (auto_mount_handlers_
[i
].Run(url_request
, filesystem_url
,
400 storage_domain
, callback
)) {
405 callback
.Run(base::File::FILE_ERROR_NOT_FOUND
);
408 void FileSystemContext::DeleteFileSystem(
409 const GURL
& origin_url
,
411 const StatusCallback
& callback
) {
412 DCHECK(io_task_runner_
->RunsTasksOnCurrentThread());
413 DCHECK(origin_url
== origin_url
.GetOrigin());
414 DCHECK(!callback
.is_null());
416 FileSystemBackend
* backend
= GetFileSystemBackend(type
);
418 callback
.Run(base::File::FILE_ERROR_SECURITY
);
421 if (!backend
->GetQuotaUtil()) {
422 callback
.Run(base::File::FILE_ERROR_INVALID_OPERATION
);
426 base::PostTaskAndReplyWithResult(
427 default_file_task_runner(),
429 // It is safe to pass Unretained(quota_util) since context owns it.
430 base::Bind(&FileSystemQuotaUtil::DeleteOriginDataOnFileTaskRunner
,
431 base::Unretained(backend
->GetQuotaUtil()),
432 make_scoped_refptr(this),
433 base::Unretained(quota_manager_proxy()),
439 scoped_ptr
<storage::FileStreamReader
> FileSystemContext::CreateFileStreamReader(
440 const FileSystemURL
& url
,
442 int64 max_bytes_to_read
,
443 const base::Time
& expected_modification_time
) {
445 return scoped_ptr
<storage::FileStreamReader
>();
446 FileSystemBackend
* backend
= GetFileSystemBackend(url
.type());
448 return scoped_ptr
<storage::FileStreamReader
>();
449 return backend
->CreateFileStreamReader(
450 url
, offset
, max_bytes_to_read
, expected_modification_time
, this);
453 scoped_ptr
<FileStreamWriter
> FileSystemContext::CreateFileStreamWriter(
454 const FileSystemURL
& url
,
457 return scoped_ptr
<FileStreamWriter
>();
458 FileSystemBackend
* backend
= GetFileSystemBackend(url
.type());
460 return scoped_ptr
<FileStreamWriter
>();
461 return backend
->CreateFileStreamWriter(url
, offset
, this);
464 scoped_ptr
<FileSystemOperationRunner
>
465 FileSystemContext::CreateFileSystemOperationRunner() {
466 return make_scoped_ptr(new FileSystemOperationRunner(this));
469 FileSystemURL
FileSystemContext::CrackURL(const GURL
& url
) const {
470 return CrackFileSystemURL(FileSystemURL(url
));
473 FileSystemURL
FileSystemContext::CreateCrackedFileSystemURL(
476 const base::FilePath
& path
) const {
477 return CrackFileSystemURL(FileSystemURL(origin
, type
, path
));
480 #if defined(OS_CHROMEOS)
481 void FileSystemContext::EnableTemporaryFileSystemInIncognito() {
482 sandbox_backend_
->set_enable_temporary_file_system_in_incognito(true);
486 bool FileSystemContext::CanServeURLRequest(const FileSystemURL
& url
) const {
487 // We never support accessing files in isolated filesystems via an URL.
488 if (url
.mount_type() == kFileSystemTypeIsolated
)
490 #if defined(OS_CHROMEOS)
491 if (url
.type() == kFileSystemTypeTemporary
&&
492 sandbox_backend_
->enable_temporary_file_system_in_incognito()) {
496 return !is_incognito_
|| !FileSystemContext::IsSandboxFileSystem(url
.type());
499 void FileSystemContext::OpenPluginPrivateFileSystem(
500 const GURL
& origin_url
,
502 const std::string
& filesystem_id
,
503 const std::string
& plugin_id
,
504 OpenFileSystemMode mode
,
505 const StatusCallback
& callback
) {
506 DCHECK(plugin_private_backend_
);
507 plugin_private_backend_
->OpenPrivateFileSystem(
508 origin_url
, type
, filesystem_id
, plugin_id
, mode
, callback
);
511 FileSystemContext::~FileSystemContext() {
514 void FileSystemContext::DeleteOnCorrectThread() const {
515 if (!io_task_runner_
->RunsTasksOnCurrentThread() &&
516 io_task_runner_
->DeleteSoon(FROM_HERE
, this)) {
522 FileSystemOperation
* FileSystemContext::CreateFileSystemOperation(
523 const FileSystemURL
& url
, base::File::Error
* error_code
) {
524 if (!url
.is_valid()) {
526 *error_code
= base::File::FILE_ERROR_INVALID_URL
;
530 FileSystemBackend
* backend
= GetFileSystemBackend(url
.type());
533 *error_code
= base::File::FILE_ERROR_FAILED
;
537 base::File::Error fs_error
= base::File::FILE_OK
;
538 FileSystemOperation
* operation
=
539 backend
->CreateFileSystemOperation(url
, this, &fs_error
);
542 *error_code
= fs_error
;
546 FileSystemURL
FileSystemContext::CrackFileSystemURL(
547 const FileSystemURL
& url
) const {
549 return FileSystemURL();
551 // The returned value in case there is no crackers which can crack the url.
552 // This is valid situation for non isolated/external file systems.
553 FileSystemURL current
= url
;
555 // File system may be mounted multiple times (e.g., an isolated filesystem on
556 // top of an external filesystem). Hence cracking needs to be iterated.
558 FileSystemURL cracked
= current
;
559 for (size_t i
= 0; i
< url_crackers_
.size(); ++i
) {
560 if (!url_crackers_
[i
]->HandlesFileSystemMountType(current
.type()))
562 cracked
= url_crackers_
[i
]->CrackFileSystemURL(current
);
563 if (cracked
.is_valid())
566 if (cracked
== current
)
573 void FileSystemContext::RegisterBackend(FileSystemBackend
* backend
) {
574 const FileSystemType mount_types
[] = {
575 kFileSystemTypeTemporary
,
576 kFileSystemTypePersistent
,
577 kFileSystemTypeIsolated
,
578 kFileSystemTypeExternal
,
580 // Register file system backends for public mount types.
581 for (size_t j
= 0; j
< arraysize(mount_types
); ++j
) {
582 if (backend
->CanHandleType(mount_types
[j
])) {
583 const bool inserted
= backend_map_
.insert(
584 std::make_pair(mount_types
[j
], backend
)).second
;
588 // Register file system backends for internal types.
589 for (int t
= kFileSystemInternalTypeEnumStart
+ 1;
590 t
< kFileSystemInternalTypeEnumEnd
; ++t
) {
591 FileSystemType type
= static_cast<FileSystemType
>(t
);
592 if (backend
->CanHandleType(type
)) {
593 const bool inserted
= backend_map_
.insert(
594 std::make_pair(type
, backend
)).second
;
600 void FileSystemContext::DidOpenFileSystemForResolveURL(
601 const FileSystemURL
& url
,
602 const FileSystemContext::ResolveURLCallback
& callback
,
603 const GURL
& filesystem_root
,
604 const std::string
& filesystem_name
,
605 base::File::Error error
) {
606 DCHECK(io_task_runner_
->RunsTasksOnCurrentThread());
608 if (error
!= base::File::FILE_OK
) {
609 callback
.Run(error
, FileSystemInfo(), base::FilePath(),
610 FileSystemContext::RESOLVED_ENTRY_NOT_FOUND
);
614 storage::FileSystemInfo
info(
615 filesystem_name
, filesystem_root
, url
.mount_type());
617 // Extract the virtual path not containing a filesystem type part from |url|.
618 base::FilePath parent
= CrackURL(filesystem_root
).virtual_path();
619 base::FilePath child
= url
.virtual_path();
622 if (parent
.empty()) {
624 } else if (parent
!= child
) {
625 bool result
= parent
.AppendRelativePath(child
, &path
);
629 operation_runner()->GetMetadata(
630 url
, base::Bind(&DidGetMetadataForResolveURL
, path
, callback
, info
));
633 } // namespace storage