// Copyright 2013 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/plugin_private_file_system_backend.h" #include <map> #include "base/stl_util.h" #include "base/synchronization/lock.h" #include "base/task_runner_util.h" #include "net/base/net_util.h" #include "webkit/browser/blob/file_stream_reader.h" #include "webkit/browser/fileapi/async_file_util_adapter.h" #include "webkit/browser/fileapi/file_stream_writer.h" #include "webkit/browser/fileapi/file_system_context.h" #include "webkit/browser/fileapi/file_system_operation.h" #include "webkit/browser/fileapi/file_system_operation_context.h" #include "webkit/browser/fileapi/file_system_options.h" #include "webkit/browser/fileapi/isolated_context.h" #include "webkit/browser/fileapi/obfuscated_file_util.h" #include "webkit/browser/fileapi/quota/quota_reservation.h" #include "webkit/common/fileapi/file_system_util.h" namespace fileapi { class PluginPrivateFileSystemBackend::FileSystemIDToPluginMap { public: explicit FileSystemIDToPluginMap(base::SequencedTaskRunner* task_runner) : task_runner_(task_runner) {} ~FileSystemIDToPluginMap() {} std::string GetPluginIDForURL(const FileSystemURL& url) { DCHECK(task_runner_->RunsTasksOnCurrentThread()); Map::iterator found = map_.find(url.filesystem_id()); if (url.type() != kFileSystemTypePluginPrivate || found == map_.end()) { NOTREACHED() << "Unsupported url is given: " << url.DebugString(); return std::string(); } return found->second; } void RegisterFileSystem(const std::string& filesystem_id, const std::string& plugin_id) { DCHECK(task_runner_->RunsTasksOnCurrentThread()); DCHECK(!filesystem_id.empty()); DCHECK(!ContainsKey(map_, filesystem_id)) << filesystem_id; map_[filesystem_id] = plugin_id; } void RemoveFileSystem(const std::string& filesystem_id) { DCHECK(task_runner_->RunsTasksOnCurrentThread()); map_.erase(filesystem_id); } private: typedef std::map<std::string, std::string> Map; scoped_refptr<base::SequencedTaskRunner> task_runner_; Map map_; }; namespace { const base::FilePath::CharType* kFileSystemDirectory = SandboxFileSystemBackendDelegate::kFileSystemDirectory; const base::FilePath::CharType* kPluginPrivateDirectory = FILE_PATH_LITERAL("Plugins"); base::File::Error OpenFileSystemOnFileTaskRunner( ObfuscatedFileUtil* file_util, PluginPrivateFileSystemBackend::FileSystemIDToPluginMap* plugin_map, const GURL& origin_url, const std::string& filesystem_id, const std::string& plugin_id, OpenFileSystemMode mode) { base::File::Error error = base::File::FILE_ERROR_FAILED; const bool create = (mode == OPEN_FILE_SYSTEM_CREATE_IF_NONEXISTENT); file_util->GetDirectoryForOriginAndType( origin_url, plugin_id, create, &error); if (error == base::File::FILE_OK) plugin_map->RegisterFileSystem(filesystem_id, plugin_id); return error; } } // namespace PluginPrivateFileSystemBackend::PluginPrivateFileSystemBackend( base::SequencedTaskRunner* file_task_runner, const base::FilePath& profile_path, quota::SpecialStoragePolicy* special_storage_policy, const FileSystemOptions& file_system_options) : file_task_runner_(file_task_runner), file_system_options_(file_system_options), base_path_(profile_path.Append( kFileSystemDirectory).Append(kPluginPrivateDirectory)), plugin_map_(new FileSystemIDToPluginMap(file_task_runner)), weak_factory_(this) { file_util_.reset( new AsyncFileUtilAdapter(new ObfuscatedFileUtil( special_storage_policy, base_path_, file_system_options.env_override(), file_task_runner, base::Bind(&FileSystemIDToPluginMap::GetPluginIDForURL, base::Owned(plugin_map_)), std::set<std::string>(), NULL))); } PluginPrivateFileSystemBackend::~PluginPrivateFileSystemBackend() { if (!file_task_runner_->RunsTasksOnCurrentThread()) { AsyncFileUtil* file_util = file_util_.release(); if (!file_task_runner_->DeleteSoon(FROM_HERE, file_util)) delete file_util; } } void PluginPrivateFileSystemBackend::OpenPrivateFileSystem( const GURL& origin_url, FileSystemType type, const std::string& filesystem_id, const std::string& plugin_id, OpenFileSystemMode mode, const StatusCallback& callback) { if (!CanHandleType(type) || file_system_options_.is_incognito()) { base::MessageLoopProxy::current()->PostTask( FROM_HERE, base::Bind(callback, base::File::FILE_ERROR_SECURITY)); return; } PostTaskAndReplyWithResult( file_task_runner_.get(), FROM_HERE, base::Bind(&OpenFileSystemOnFileTaskRunner, obfuscated_file_util(), plugin_map_, origin_url, filesystem_id, plugin_id, mode), callback); } bool PluginPrivateFileSystemBackend::CanHandleType(FileSystemType type) const { return type == kFileSystemTypePluginPrivate; } void PluginPrivateFileSystemBackend::Initialize(FileSystemContext* context) { } void PluginPrivateFileSystemBackend::ResolveURL( const FileSystemURL& url, OpenFileSystemMode mode, const OpenFileSystemCallback& callback) { // We never allow opening a new plugin-private filesystem via usual // ResolveURL. base::MessageLoopProxy::current()->PostTask( FROM_HERE, base::Bind(callback, GURL(), std::string(), base::File::FILE_ERROR_SECURITY)); } AsyncFileUtil* PluginPrivateFileSystemBackend::GetAsyncFileUtil(FileSystemType type) { return file_util_.get(); } CopyOrMoveFileValidatorFactory* PluginPrivateFileSystemBackend::GetCopyOrMoveFileValidatorFactory( FileSystemType type, base::File::Error* error_code) { DCHECK(error_code); *error_code = base::File::FILE_OK; return NULL; } FileSystemOperation* PluginPrivateFileSystemBackend::CreateFileSystemOperation( const FileSystemURL& url, FileSystemContext* context, base::File::Error* error_code) const { scoped_ptr<FileSystemOperationContext> operation_context( new FileSystemOperationContext(context)); return FileSystemOperation::Create(url, context, operation_context.Pass()); } bool PluginPrivateFileSystemBackend::SupportsStreaming( const fileapi::FileSystemURL& url) const { return false; } scoped_ptr<webkit_blob::FileStreamReader> PluginPrivateFileSystemBackend::CreateFileStreamReader( const FileSystemURL& url, int64 offset, const base::Time& expected_modification_time, FileSystemContext* context) const { return scoped_ptr<webkit_blob::FileStreamReader>(); } scoped_ptr<FileStreamWriter> PluginPrivateFileSystemBackend::CreateFileStreamWriter( const FileSystemURL& url, int64 offset, FileSystemContext* context) const { return scoped_ptr<FileStreamWriter>(); } FileSystemQuotaUtil* PluginPrivateFileSystemBackend::GetQuotaUtil() { return this; } base::File::Error PluginPrivateFileSystemBackend::DeleteOriginDataOnFileTaskRunner( FileSystemContext* context, quota::QuotaManagerProxy* proxy, const GURL& origin_url, FileSystemType type) { if (!CanHandleType(type)) return base::File::FILE_ERROR_SECURITY; bool result = obfuscated_file_util()->DeleteDirectoryForOriginAndType( origin_url, std::string()); if (result) return base::File::FILE_OK; return base::File::FILE_ERROR_FAILED; } void PluginPrivateFileSystemBackend::GetOriginsForTypeOnFileTaskRunner( FileSystemType type, std::set<GURL>* origins) { if (!CanHandleType(type)) return; scoped_ptr<ObfuscatedFileUtil::AbstractOriginEnumerator> enumerator( obfuscated_file_util()->CreateOriginEnumerator()); GURL origin; while (!(origin = enumerator->Next()).is_empty()) origins->insert(origin); } void PluginPrivateFileSystemBackend::GetOriginsForHostOnFileTaskRunner( FileSystemType type, const std::string& host, std::set<GURL>* origins) { if (!CanHandleType(type)) return; scoped_ptr<ObfuscatedFileUtil::AbstractOriginEnumerator> enumerator( obfuscated_file_util()->CreateOriginEnumerator()); GURL origin; while (!(origin = enumerator->Next()).is_empty()) { if (host == net::GetHostOrSpecFromURL(origin)) origins->insert(origin); } } int64 PluginPrivateFileSystemBackend::GetOriginUsageOnFileTaskRunner( FileSystemContext* context, const GURL& origin_url, FileSystemType type) { // We don't track usage on this filesystem. return 0; } scoped_refptr<QuotaReservation> PluginPrivateFileSystemBackend::CreateQuotaReservationOnFileTaskRunner( const GURL& origin_url, FileSystemType type) { // We don't track usage on this filesystem. NOTREACHED(); return scoped_refptr<QuotaReservation>(); } void PluginPrivateFileSystemBackend::AddFileUpdateObserver( FileSystemType type, FileUpdateObserver* observer, base::SequencedTaskRunner* task_runner) {} void PluginPrivateFileSystemBackend::AddFileChangeObserver( FileSystemType type, FileChangeObserver* observer, base::SequencedTaskRunner* task_runner) {} void PluginPrivateFileSystemBackend::AddFileAccessObserver( FileSystemType type, FileAccessObserver* observer, base::SequencedTaskRunner* task_runner) {} const UpdateObserverList* PluginPrivateFileSystemBackend::GetUpdateObservers( FileSystemType type) const { return NULL; } const ChangeObserverList* PluginPrivateFileSystemBackend::GetChangeObservers( FileSystemType type) const { return NULL; } const AccessObserverList* PluginPrivateFileSystemBackend::GetAccessObservers( FileSystemType type) const { return NULL; } ObfuscatedFileUtil* PluginPrivateFileSystemBackend::obfuscated_file_util() { return static_cast<ObfuscatedFileUtil*>( static_cast<AsyncFileUtilAdapter*>(file_util_.get())->sync_file_util()); } } // namespace fileapi