blob: 6fd65cf32fb4fad2ca6386d53293aa0c590486d9 [file] [log] [blame]
// 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