blob: c8bb838d81c7e8a310164e499cdd1882e0192696 [file] [log] [blame]
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "webkit/browser/fileapi/file_system_context.h"
#include "base/bind.h"
#include "base/single_thread_task_runner.h"
#include "base/stl_util.h"
#include "googleurl/src/gurl.h"
#include "webkit/browser/blob/file_stream_reader.h"
#include "webkit/browser/fileapi/copy_or_move_file_validator.h"
#include "webkit/browser/fileapi/external_mount_points.h"
#include "webkit/browser/fileapi/file_stream_writer.h"
#include "webkit/browser/fileapi/file_system_file_util.h"
#include "webkit/browser/fileapi/file_system_operation.h"
#include "webkit/browser/fileapi/file_system_options.h"
#include "webkit/browser/fileapi/file_system_quota_client.h"
#include "webkit/browser/fileapi/file_system_task_runners.h"
#include "webkit/browser/fileapi/file_system_url.h"
#include "webkit/browser/fileapi/isolated_context.h"
#include "webkit/browser/fileapi/isolated_mount_point_provider.h"
#include "webkit/browser/fileapi/mount_points.h"
#include "webkit/browser/fileapi/sandbox_mount_point_provider.h"
#include "webkit/browser/fileapi/syncable/local_file_change_tracker.h"
#include "webkit/browser/fileapi/syncable/local_file_sync_context.h"
#include "webkit/browser/fileapi/syncable/syncable_file_system_util.h"
#include "webkit/browser/fileapi/test_mount_point_provider.h"
#include "webkit/browser/quota/quota_manager.h"
#include "webkit/browser/quota/special_storage_policy.h"
#include "webkit/common/fileapi/file_system_util.h"
#if defined(OS_CHROMEOS)
#include "webkit/browser/chromeos/fileapi/cros_mount_point_provider.h"
#endif
using quota::QuotaClient;
namespace fileapi {
namespace {
QuotaClient* CreateQuotaClient(
FileSystemContext* context,
bool is_incognito) {
return new FileSystemQuotaClient(context, is_incognito);
}
void DidOpenFileSystem(
const FileSystemContext::OpenFileSystemCallback& callback,
const GURL& filesystem_root,
const std::string& filesystem_name,
base::PlatformFileError error) {
callback.Run(error, filesystem_name, filesystem_root);
}
} // namespace
FileSystemContext::FileSystemContext(
scoped_ptr<FileSystemTaskRunners> task_runners,
ExternalMountPoints* external_mount_points,
quota::SpecialStoragePolicy* special_storage_policy,
quota::QuotaManagerProxy* quota_manager_proxy,
ScopedVector<FileSystemMountPointProvider> additional_providers,
const base::FilePath& partition_path,
const FileSystemOptions& options)
: task_runners_(task_runners.Pass()),
quota_manager_proxy_(quota_manager_proxy),
sandbox_provider_(
new SandboxMountPointProvider(
quota_manager_proxy,
task_runners_->file_task_runner(),
partition_path,
options,
special_storage_policy)),
isolated_provider_(new IsolatedMountPointProvider()),
additional_providers_(additional_providers.Pass()),
external_mount_points_(external_mount_points),
partition_path_(partition_path) {
DCHECK(task_runners_.get());
if (quota_manager_proxy) {
quota_manager_proxy->RegisterClient(CreateQuotaClient(
this, options.is_incognito()));
}
RegisterMountPointProvider(sandbox_provider_.get());
RegisterMountPointProvider(isolated_provider_.get());
#if defined(OS_CHROMEOS)
// TODO(kinuko): Move this out of webkit/fileapi layer.
DCHECK(external_mount_points);
external_provider_.reset(
new chromeos::CrosMountPointProvider(
special_storage_policy,
external_mount_points,
ExternalMountPoints::GetSystemInstance()));
RegisterMountPointProvider(external_provider_.get());
#endif
for (ScopedVector<FileSystemMountPointProvider>::const_iterator iter =
additional_providers_.begin();
iter != additional_providers_.end(); ++iter) {
RegisterMountPointProvider(*iter);
}
// Additional mount points must be added before regular system-wide
// mount points.
if (external_mount_points)
url_crackers_.push_back(external_mount_points);
url_crackers_.push_back(ExternalMountPoints::GetSystemInstance());
url_crackers_.push_back(IsolatedContext::GetInstance());
}
bool FileSystemContext::DeleteDataForOriginOnFileThread(
const GURL& origin_url) {
DCHECK(task_runners_->file_task_runner()->RunsTasksOnCurrentThread());
DCHECK(sandbox_provider());
DCHECK(origin_url == origin_url.GetOrigin());
// Delete temporary and persistent data.
return
(sandbox_provider()->DeleteOriginDataOnFileThread(
this, quota_manager_proxy(), origin_url,
kFileSystemTypeTemporary) ==
base::PLATFORM_FILE_OK) &&
(sandbox_provider()->DeleteOriginDataOnFileThread(
this, quota_manager_proxy(), origin_url,
kFileSystemTypePersistent) ==
base::PLATFORM_FILE_OK) &&
(sandbox_provider()->DeleteOriginDataOnFileThread(
this, quota_manager_proxy(), origin_url,
kFileSystemTypeSyncable) ==
base::PLATFORM_FILE_OK);
}
FileSystemQuotaUtil*
FileSystemContext::GetQuotaUtil(FileSystemType type) const {
FileSystemMountPointProvider* mount_point_provider =
GetMountPointProvider(type);
if (!mount_point_provider)
return NULL;
return mount_point_provider->GetQuotaUtil();
}
AsyncFileUtil* FileSystemContext::GetAsyncFileUtil(
FileSystemType type) const {
FileSystemMountPointProvider* mount_point_provider =
GetMountPointProvider(type);
if (!mount_point_provider)
return NULL;
return mount_point_provider->GetAsyncFileUtil(type);
}
FileSystemFileUtil* FileSystemContext::GetFileUtil(
FileSystemType type) const {
FileSystemMountPointProvider* mount_point_provider =
GetMountPointProvider(type);
if (!mount_point_provider)
return NULL;
return mount_point_provider->GetFileUtil(type);
}
CopyOrMoveFileValidatorFactory*
FileSystemContext::GetCopyOrMoveFileValidatorFactory(
FileSystemType type, base::PlatformFileError* error_code) const {
DCHECK(error_code);
*error_code = base::PLATFORM_FILE_OK;
FileSystemMountPointProvider* mount_point_provider =
GetMountPointProvider(type);
if (!mount_point_provider)
return NULL;
return mount_point_provider->GetCopyOrMoveFileValidatorFactory(
type, error_code);
}
FileSystemMountPointProvider* FileSystemContext::GetMountPointProvider(
FileSystemType type) const {
MountPointProviderMap::const_iterator found = provider_map_.find(type);
if (found != provider_map_.end())
return found->second;
NOTREACHED() << "Unknown filesystem type: " << type;
return NULL;
}
const UpdateObserverList* FileSystemContext::GetUpdateObservers(
FileSystemType type) const {
// Currently update observer is only available in SandboxMountPointProvider
// and TestMountPointProvider.
// TODO(kinuko): Probably GetUpdateObservers() virtual method should be
// added to FileSystemMountPointProvider interface and be called like
// other GetFoo() methods do.
if (SandboxMountPointProvider::IsSandboxType(type))
return sandbox_provider()->GetUpdateObservers(type);
if (type != kFileSystemTypeTest)
return NULL;
FileSystemMountPointProvider* mount_point_provider =
GetMountPointProvider(type);
return static_cast<TestMountPointProvider*>(
mount_point_provider)->GetUpdateObservers(type);
}
SandboxMountPointProvider*
FileSystemContext::sandbox_provider() const {
return sandbox_provider_.get();
}
ExternalFileSystemMountPointProvider*
FileSystemContext::external_provider() const {
return external_provider_.get();
}
void FileSystemContext::OpenFileSystem(
const GURL& origin_url,
FileSystemType type,
OpenFileSystemMode mode,
const OpenFileSystemCallback& callback) {
DCHECK(!callback.is_null());
FileSystemMountPointProvider* mount_point_provider =
GetMountPointProvider(type);
if (!mount_point_provider) {
callback.Run(base::PLATFORM_FILE_ERROR_SECURITY, std::string(), GURL());
return;
}
GURL root_url = GetFileSystemRootURI(origin_url, type);
std::string name = GetFileSystemName(origin_url, type);
mount_point_provider->OpenFileSystem(
origin_url, type, mode,
base::Bind(&DidOpenFileSystem, callback, root_url, name));
}
void FileSystemContext::OpenSyncableFileSystem(
const std::string& mount_name,
const GURL& origin_url,
FileSystemType type,
OpenFileSystemMode mode,
const OpenFileSystemCallback& callback) {
DCHECK(!callback.is_null());
DCHECK(type == kFileSystemTypeSyncable);
GURL root_url = sync_file_system::GetSyncableFileSystemRootURI(
origin_url, mount_name);
std::string name = GetFileSystemName(origin_url, kFileSystemTypeSyncable);
FileSystemMountPointProvider* mount_point_provider =
GetMountPointProvider(type);
DCHECK(mount_point_provider);
mount_point_provider->OpenFileSystem(
origin_url, type, mode,
base::Bind(&DidOpenFileSystem, callback, root_url, name));
}
void FileSystemContext::DeleteFileSystem(
const GURL& origin_url,
FileSystemType type,
const DeleteFileSystemCallback& callback) {
DCHECK(origin_url == origin_url.GetOrigin());
FileSystemMountPointProvider* mount_point_provider =
GetMountPointProvider(type);
if (!mount_point_provider) {
callback.Run(base::PLATFORM_FILE_ERROR_SECURITY);
return;
}
mount_point_provider->DeleteFileSystem(origin_url, type, this, callback);
}
FileSystemOperation* FileSystemContext::CreateFileSystemOperation(
const FileSystemURL& url, base::PlatformFileError* error_code) {
if (!url.is_valid()) {
if (error_code)
*error_code = base::PLATFORM_FILE_ERROR_INVALID_URL;
return NULL;
}
FileSystemMountPointProvider* mount_point_provider =
GetMountPointProvider(url.type());
if (!mount_point_provider) {
if (error_code)
*error_code = base::PLATFORM_FILE_ERROR_FAILED;
return NULL;
}
base::PlatformFileError fs_error = base::PLATFORM_FILE_OK;
FileSystemOperation* operation =
mount_point_provider->CreateFileSystemOperation(url, this, &fs_error);
if (error_code)
*error_code = fs_error;
return operation;
}
scoped_ptr<webkit_blob::FileStreamReader>
FileSystemContext::CreateFileStreamReader(
const FileSystemURL& url,
int64 offset,
const base::Time& expected_modification_time) {
if (!url.is_valid())
return scoped_ptr<webkit_blob::FileStreamReader>();
FileSystemMountPointProvider* mount_point_provider =
GetMountPointProvider(url.type());
if (!mount_point_provider)
return scoped_ptr<webkit_blob::FileStreamReader>();
return mount_point_provider->CreateFileStreamReader(
url, offset, expected_modification_time, this);
}
scoped_ptr<FileStreamWriter> FileSystemContext::CreateFileStreamWriter(
const FileSystemURL& url,
int64 offset) {
if (!url.is_valid())
return scoped_ptr<FileStreamWriter>();
FileSystemMountPointProvider* mount_point_provider =
GetMountPointProvider(url.type());
if (!mount_point_provider)
return scoped_ptr<FileStreamWriter>();
return mount_point_provider->CreateFileStreamWriter(url, offset, this);
}
void FileSystemContext::SetLocalFileChangeTracker(
scoped_ptr<sync_file_system::LocalFileChangeTracker> tracker) {
DCHECK(!change_tracker_.get());
DCHECK(tracker.get());
change_tracker_ = tracker.Pass();
sandbox_provider_->AddSyncableFileUpdateObserver(
change_tracker_.get(),
task_runners_->file_task_runner());
sandbox_provider_->AddSyncableFileChangeObserver(
change_tracker_.get(),
task_runners_->file_task_runner());
}
void FileSystemContext::set_sync_context(
sync_file_system::LocalFileSyncContext* sync_context) {
sync_context_ = sync_context;
}
FileSystemURL FileSystemContext::CrackURL(const GURL& url) const {
return CrackFileSystemURL(FileSystemURL(url));
}
FileSystemURL FileSystemContext::CreateCrackedFileSystemURL(
const GURL& origin,
FileSystemType type,
const base::FilePath& path) const {
return CrackFileSystemURL(FileSystemURL(origin, type, path));
}
FileSystemContext::~FileSystemContext() {
task_runners_->file_task_runner()->DeleteSoon(
FROM_HERE, change_tracker_.release());
}
void FileSystemContext::DeleteOnCorrectThread() const {
if (!task_runners_->io_task_runner()->RunsTasksOnCurrentThread() &&
task_runners_->io_task_runner()->DeleteSoon(FROM_HERE, this)) {
return;
}
delete this;
}
FileSystemURL FileSystemContext::CrackFileSystemURL(
const FileSystemURL& url) const {
if (!url.is_valid())
return FileSystemURL();
// The returned value in case there is no crackers which can crack the url.
// This is valid situation for non isolated/external file systems.
FileSystemURL current = url;
// File system may be mounted multiple times (e.g., an isolated filesystem on
// top of an external filesystem). Hence cracking needs to be iterated.
for (;;) {
FileSystemURL cracked = current;
for (size_t i = 0; i < url_crackers_.size(); ++i) {
if (!url_crackers_[i]->HandlesFileSystemMountType(current.type()))
continue;
cracked = url_crackers_[i]->CrackFileSystemURL(current);
if (cracked.is_valid())
break;
}
if (cracked == current)
break;
current = cracked;
}
return current;
}
void FileSystemContext::RegisterMountPointProvider(
FileSystemMountPointProvider* provider) {
const FileSystemType mount_types[] = {
kFileSystemTypeTemporary,
kFileSystemTypePersistent,
kFileSystemTypeIsolated,
kFileSystemTypeExternal,
};
// Register mount point providers for public mount types.
for (size_t j = 0; j < ARRAYSIZE_UNSAFE(mount_types); ++j) {
if (provider->CanHandleType(mount_types[j])) {
const bool inserted = provider_map_.insert(
std::make_pair(mount_types[j], provider)).second;
DCHECK(inserted);
}
}
// Register mount point providers for internal types.
for (int t = kFileSystemInternalTypeEnumStart + 1;
t < kFileSystemInternalTypeEnumEnd; ++t) {
FileSystemType type = static_cast<FileSystemType>(t);
if (provider->CanHandleType(type)) {
const bool inserted = provider_map_.insert(
std::make_pair(type, provider)).second;
DCHECK(inserted);
}
}
}
} // namespace fileapi