| // 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 "storage/browser/fileapi/plugin_private_file_system_backend.h" |
| |
| #include <stdint.h> |
| |
| #include <map> |
| #include <memory> |
| #include <utility> |
| |
| #include "base/stl_util.h" |
| #include "base/synchronization/lock.h" |
| #include "base/task_runner_util.h" |
| #include "base/thread_task_runner_handle.h" |
| #include "net/base/url_util.h" |
| #include "storage/browser/fileapi/async_file_util_adapter.h" |
| #include "storage/browser/fileapi/file_stream_reader.h" |
| #include "storage/browser/fileapi/file_stream_writer.h" |
| #include "storage/browser/fileapi/file_system_context.h" |
| #include "storage/browser/fileapi/file_system_operation.h" |
| #include "storage/browser/fileapi/file_system_operation_context.h" |
| #include "storage/browser/fileapi/isolated_context.h" |
| #include "storage/browser/fileapi/obfuscated_file_util.h" |
| #include "storage/browser/fileapi/quota/quota_reservation.h" |
| #include "storage/common/fileapi/file_system_util.h" |
| |
| namespace storage { |
| |
| 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, |
| storage::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::ThreadTaskRunnerHandle::Get()->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::ThreadTaskRunnerHandle::Get()->PostTask( |
| FROM_HERE, |
| base::Bind(callback, GURL(), std::string(), |
| base::File::FILE_ERROR_SECURITY)); |
| } |
| |
| AsyncFileUtil* |
| PluginPrivateFileSystemBackend::GetAsyncFileUtil(FileSystemType type) { |
| return file_util_.get(); |
| } |
| |
| WatcherManager* PluginPrivateFileSystemBackend::GetWatcherManager( |
| FileSystemType type) { |
| return NULL; |
| } |
| |
| 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 { |
| std::unique_ptr<FileSystemOperationContext> operation_context( |
| new FileSystemOperationContext(context)); |
| return FileSystemOperation::Create(url, context, |
| std::move(operation_context)); |
| } |
| |
| bool PluginPrivateFileSystemBackend::SupportsStreaming( |
| const storage::FileSystemURL& url) const { |
| return false; |
| } |
| |
| bool PluginPrivateFileSystemBackend::HasInplaceCopyImplementation( |
| storage::FileSystemType type) const { |
| return false; |
| } |
| |
| std::unique_ptr<storage::FileStreamReader> |
| PluginPrivateFileSystemBackend::CreateFileStreamReader( |
| const FileSystemURL& url, |
| int64_t offset, |
| int64_t max_bytes_to_read, |
| const base::Time& expected_modification_time, |
| FileSystemContext* context) const { |
| return std::unique_ptr<storage::FileStreamReader>(); |
| } |
| |
| std::unique_ptr<FileStreamWriter> |
| PluginPrivateFileSystemBackend::CreateFileStreamWriter( |
| const FileSystemURL& url, |
| int64_t offset, |
| FileSystemContext* context) const { |
| return std::unique_ptr<FileStreamWriter>(); |
| } |
| |
| FileSystemQuotaUtil* PluginPrivateFileSystemBackend::GetQuotaUtil() { |
| return this; |
| } |
| |
| base::File::Error |
| PluginPrivateFileSystemBackend::DeleteOriginDataOnFileTaskRunner( |
| FileSystemContext* context, |
| storage::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; |
| std::unique_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; |
| std::unique_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_t 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>(); |
| } |
| |
| 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 storage |