Include all dupe types (event when value is zero) in scan stats.
[chromium-blink-merge.git] / storage / browser / fileapi / file_system_context.cc
blob7b280c8f0874029424615457029e458e19eb495e
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"
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 "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"
32 #include "url/gurl.h"
34 using storage::QuotaClient;
36 namespace storage {
38 namespace {
40 QuotaClient* CreateQuotaClient(
41 FileSystemContext* context,
42 bool is_incognito) {
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);
57 } else {
58 callback.Run(error, FileSystemInfo(), base::FilePath(),
59 FileSystemContext::RESOLVED_ENTRY_NOT_FOUND);
61 return;
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));
79 } // namespace
81 // static
82 int FileSystemContext::GetPermissionPolicy(FileSystemType type) {
83 switch (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;
129 NOTREACHED();
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),
146 sandbox_delegate_(
147 new SandboxFileSystemBackendDelegate(quota_manager_proxy,
148 file_task_runner,
149 partition_path,
150 special_storage_policy,
151 options)),
152 sandbox_backend_(new SandboxFileSystemBackend(sandbox_delegate_.get())),
153 plugin_private_backend_(
154 new PluginPrivateFileSystemBackend(file_task_runner,
155 partition_path,
156 special_storage_policy,
157 options)),
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
177 // types.
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
199 // mount points.
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());
211 bool success = true;
212 for (FileSystemBackendMap::iterator iter = backend_map_.begin();
213 iter != backend_map_.end();
214 ++iter) {
215 FileSystemBackend* backend = iter->second;
216 if (!backend->GetQuotaUtil())
217 continue;
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.
222 success = false;
226 return success;
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(
238 origin_url, type);
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)));
246 return;
248 operation_runner_->Shutdown();
251 FileSystemQuotaUtil*
252 FileSystemContext::GetQuotaUtil(FileSystemType type) const {
253 FileSystemBackend* backend = GetFileSystemBackend(type);
254 if (!backend)
255 return NULL;
256 return backend->GetQuotaUtil();
259 AsyncFileUtil* FileSystemContext::GetAsyncFileUtil(
260 FileSystemType type) const {
261 FileSystemBackend* backend = GetFileSystemBackend(type);
262 if (!backend)
263 return NULL;
264 return backend->GetAsyncFileUtil(type);
267 CopyOrMoveFileValidatorFactory*
268 FileSystemContext::GetCopyOrMoveFileValidatorFactory(
269 FileSystemType type, base::File::Error* error_code) const {
270 DCHECK(error_code);
271 *error_code = base::File::FILE_OK;
272 FileSystemBackend* backend = GetFileSystemBackend(type);
273 if (!backend)
274 return NULL;
275 return backend->GetCopyOrMoveFileValidatorFactory(
276 type, error_code);
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;
285 return NULL;
288 WatcherManager* FileSystemContext::GetWatcherManager(
289 FileSystemType type) const {
290 FileSystemBackend* backend = GetFileSystemBackend(type);
291 if (!backend)
292 return NULL;
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 {
321 types->clear();
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,
335 FileSystemType type,
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);
344 return;
347 FileSystemBackend* backend = GetFileSystemBackend(type);
348 if (!backend) {
349 callback.Run(GURL(), std::string(), base::File::FILE_ERROR_SECURITY);
350 return;
353 backend->ResolveURL(
354 CreateCrackedFileSystemURL(origin_url, type, base::FilePath()),
355 mode,
356 callback);
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(
370 FROM_HERE,
371 base::Bind(&FileSystemContext::ResolveURL, this, url, relay_callback));
372 return;
375 FileSystemBackend* backend = GetFileSystemBackend(url.type());
376 if (!backend) {
377 callback.Run(base::File::FILE_ERROR_SECURITY,
378 FileSystemInfo(), base::FilePath(),
379 FileSystemContext::RESOLVED_ENTRY_NOT_FOUND);
380 return;
383 backend->ResolveURL(
384 url,
385 OPEN_FILE_SYSTEM_FAIL_IF_NONEXISTENT,
386 base::Bind(&FileSystemContext::DidOpenFileSystemForResolveURL,
387 this,
388 url,
389 callback));
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)) {
401 return;
405 callback.Run(base::File::FILE_ERROR_NOT_FOUND);
408 void FileSystemContext::DeleteFileSystem(
409 const GURL& origin_url,
410 FileSystemType type,
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);
417 if (!backend) {
418 callback.Run(base::File::FILE_ERROR_SECURITY);
419 return;
421 if (!backend->GetQuotaUtil()) {
422 callback.Run(base::File::FILE_ERROR_INVALID_OPERATION);
423 return;
426 base::PostTaskAndReplyWithResult(
427 default_file_task_runner(),
428 FROM_HERE,
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()),
434 origin_url,
435 type),
436 callback);
439 scoped_ptr<storage::FileStreamReader> FileSystemContext::CreateFileStreamReader(
440 const FileSystemURL& url,
441 int64 offset,
442 int64 max_bytes_to_read,
443 const base::Time& expected_modification_time) {
444 if (!url.is_valid())
445 return scoped_ptr<storage::FileStreamReader>();
446 FileSystemBackend* backend = GetFileSystemBackend(url.type());
447 if (!backend)
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,
455 int64 offset) {
456 if (!url.is_valid())
457 return scoped_ptr<FileStreamWriter>();
458 FileSystemBackend* backend = GetFileSystemBackend(url.type());
459 if (!backend)
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(
474 const GURL& origin,
475 FileSystemType type,
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);
484 #endif
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)
489 return false;
490 #if defined(OS_CHROMEOS)
491 if (url.type() == kFileSystemTypeTemporary &&
492 sandbox_backend_->enable_temporary_file_system_in_incognito()) {
493 return true;
495 #endif
496 return !is_incognito_ || !FileSystemContext::IsSandboxFileSystem(url.type());
499 void FileSystemContext::OpenPluginPrivateFileSystem(
500 const GURL& origin_url,
501 FileSystemType type,
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)) {
517 return;
519 delete this;
522 FileSystemOperation* FileSystemContext::CreateFileSystemOperation(
523 const FileSystemURL& url, base::File::Error* error_code) {
524 if (!url.is_valid()) {
525 if (error_code)
526 *error_code = base::File::FILE_ERROR_INVALID_URL;
527 return NULL;
530 FileSystemBackend* backend = GetFileSystemBackend(url.type());
531 if (!backend) {
532 if (error_code)
533 *error_code = base::File::FILE_ERROR_FAILED;
534 return NULL;
537 base::File::Error fs_error = base::File::FILE_OK;
538 FileSystemOperation* operation =
539 backend->CreateFileSystemOperation(url, this, &fs_error);
541 if (error_code)
542 *error_code = fs_error;
543 return operation;
546 FileSystemURL FileSystemContext::CrackFileSystemURL(
547 const FileSystemURL& url) const {
548 if (!url.is_valid())
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.
557 for (;;) {
558 FileSystemURL cracked = current;
559 for (size_t i = 0; i < url_crackers_.size(); ++i) {
560 if (!url_crackers_[i]->HandlesFileSystemMountType(current.type()))
561 continue;
562 cracked = url_crackers_[i]->CrackFileSystemURL(current);
563 if (cracked.is_valid())
564 break;
566 if (cracked == current)
567 break;
568 current = cracked;
570 return 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;
585 DCHECK(inserted);
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;
595 DCHECK(inserted);
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);
611 return;
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();
620 base::FilePath path;
622 if (parent.empty()) {
623 path = child;
624 } else if (parent != child) {
625 bool result = parent.AppendRelativePath(child, &path);
626 DCHECK(result);
629 operation_runner()->GetMetadata(
630 url, base::Bind(&DidGetMetadataForResolveURL, path, callback, info));
633 } // namespace storage