blob: bc7f2b6a11943ef9cc564b3faf52ad220f07e7bd [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 "content/browser/renderer_host/pepper/pepper_internal_file_ref_backend.h"
#include <string>
#include "base/callback.h"
#include "base/file_util.h"
#include "base/files/file_util_proxy.h"
#include "content/browser/child_process_security_policy_impl.h"
#include "content/browser/fileapi/browser_file_system_helper.h"
#include "content/browser/renderer_host/pepper/pepper_file_system_browser_host.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/storage_partition.h"
#include "net/base/escape.h"
#include "ppapi/c/pp_errors.h"
#include "ppapi/c/pp_file_info.h"
#include "ppapi/c/pp_instance.h"
#include "ppapi/c/pp_resource.h"
#include "ppapi/c/ppb_file_ref.h"
#include "ppapi/host/dispatch_host_message.h"
#include "ppapi/host/ppapi_host.h"
#include "ppapi/proxy/ppapi_messages.h"
#include "ppapi/shared_impl/file_ref_create_info.h"
#include "ppapi/shared_impl/file_ref_util.h"
#include "ppapi/shared_impl/file_type_conversion.h"
#include "ppapi/shared_impl/scoped_pp_var.h"
#include "ppapi/shared_impl/time_conversion.h"
#include "ppapi/shared_impl/var.h"
#include "ppapi/thunk/enter.h"
#include "ppapi/thunk/ppb_file_ref_api.h"
#include "ppapi/thunk/ppb_file_system_api.h"
#include "webkit/browser/fileapi/file_system_operation.h"
#include "webkit/browser/fileapi/file_system_operation_runner.h"
#include "webkit/browser/fileapi/file_system_url.h"
#include "webkit/common/fileapi/file_system_util.h"
using ppapi::host::PpapiHost;
using ppapi::host::ResourceHost;
namespace content {
PepperInternalFileRefBackend::PepperInternalFileRefBackend(
PpapiHost* host,
int render_process_id,
base::WeakPtr<PepperFileSystemBrowserHost> fs_host,
const std::string& path)
: host_(host),
render_process_id_(render_process_id),
fs_host_(fs_host),
fs_type_(fs_host->GetType()),
path_(path),
weak_factory_(this) {
ppapi::NormalizeInternalPath(&path_);
}
PepperInternalFileRefBackend::~PepperInternalFileRefBackend() {}
fileapi::FileSystemURL PepperInternalFileRefBackend::GetFileSystemURL() const {
if (!fs_url_.is_valid() && fs_host_.get() && fs_host_->IsOpened()) {
GURL fs_path =
fs_host_->GetRootUrl().Resolve(net::EscapePath(path_.substr(1)));
scoped_refptr<fileapi::FileSystemContext> fs_context =
GetFileSystemContext();
if (fs_context.get())
fs_url_ = fs_context->CrackURL(fs_path);
}
return fs_url_;
}
base::FilePath PepperInternalFileRefBackend::GetExternalFilePath() const {
return base::FilePath();
}
scoped_refptr<fileapi::FileSystemContext>
PepperInternalFileRefBackend::GetFileSystemContext() const {
if (!fs_host_.get())
return NULL;
return fs_host_->GetFileSystemContext();
}
void PepperInternalFileRefBackend::DidFinish(
ppapi::host::ReplyMessageContext context,
const IPC::Message& msg,
base::File::Error error) {
context.params.set_result(ppapi::FileErrorToPepperError(error));
host_->SendReply(context, msg);
}
int32_t PepperInternalFileRefBackend::MakeDirectory(
ppapi::host::ReplyMessageContext reply_context,
int32_t make_directory_flags) {
if (!GetFileSystemURL().is_valid())
return PP_ERROR_FAILED;
GetFileSystemContext()->operation_runner()->CreateDirectory(
GetFileSystemURL(),
!!(make_directory_flags & PP_MAKEDIRECTORYFLAG_EXCLUSIVE),
!!(make_directory_flags & PP_MAKEDIRECTORYFLAG_WITH_ANCESTORS),
base::Bind(&PepperInternalFileRefBackend::DidFinish,
weak_factory_.GetWeakPtr(),
reply_context,
PpapiPluginMsg_FileRef_MakeDirectoryReply()));
return PP_OK_COMPLETIONPENDING;
}
int32_t PepperInternalFileRefBackend::Touch(
ppapi::host::ReplyMessageContext reply_context,
PP_Time last_access_time,
PP_Time last_modified_time) {
if (!GetFileSystemURL().is_valid())
return PP_ERROR_FAILED;
GetFileSystemContext()->operation_runner()->TouchFile(
GetFileSystemURL(),
ppapi::PPTimeToTime(last_access_time),
ppapi::PPTimeToTime(last_modified_time),
base::Bind(&PepperInternalFileRefBackend::DidFinish,
weak_factory_.GetWeakPtr(),
reply_context,
PpapiPluginMsg_FileRef_TouchReply()));
return PP_OK_COMPLETIONPENDING;
}
int32_t PepperInternalFileRefBackend::Delete(
ppapi::host::ReplyMessageContext reply_context) {
if (!GetFileSystemURL().is_valid())
return PP_ERROR_FAILED;
GetFileSystemContext()->operation_runner()->Remove(
GetFileSystemURL(),
false,
base::Bind(&PepperInternalFileRefBackend::DidFinish,
weak_factory_.GetWeakPtr(),
reply_context,
PpapiPluginMsg_FileRef_DeleteReply()));
return PP_OK_COMPLETIONPENDING;
}
int32_t PepperInternalFileRefBackend::Rename(
ppapi::host::ReplyMessageContext reply_context,
PepperFileRefHost* new_file_ref) {
if (!GetFileSystemURL().is_valid())
return PP_ERROR_FAILED;
fileapi::FileSystemURL new_url = new_file_ref->GetFileSystemURL();
if (!new_url.is_valid())
return PP_ERROR_FAILED;
if (!new_url.IsInSameFileSystem(GetFileSystemURL()))
return PP_ERROR_FAILED;
GetFileSystemContext()->operation_runner()->Move(
GetFileSystemURL(),
new_url,
fileapi::FileSystemOperation::OPTION_NONE,
base::Bind(&PepperInternalFileRefBackend::DidFinish,
weak_factory_.GetWeakPtr(),
reply_context,
PpapiPluginMsg_FileRef_RenameReply()));
return PP_OK_COMPLETIONPENDING;
}
int32_t PepperInternalFileRefBackend::Query(
ppapi::host::ReplyMessageContext reply_context) {
if (!GetFileSystemURL().is_valid())
return PP_ERROR_FAILED;
GetFileSystemContext()->operation_runner()->GetMetadata(
GetFileSystemURL(),
base::Bind(&PepperInternalFileRefBackend::GetMetadataComplete,
weak_factory_.GetWeakPtr(),
reply_context));
return PP_OK_COMPLETIONPENDING;
}
void PepperInternalFileRefBackend::GetMetadataComplete(
ppapi::host::ReplyMessageContext reply_context,
base::File::Error error,
const base::File::Info& file_info) {
reply_context.params.set_result(ppapi::FileErrorToPepperError(error));
PP_FileInfo pp_file_info;
if (error == base::File::FILE_OK)
ppapi::FileInfoToPepperFileInfo(file_info, fs_type_, &pp_file_info);
else
memset(&pp_file_info, 0, sizeof(pp_file_info));
host_->SendReply(reply_context,
PpapiPluginMsg_FileRef_QueryReply(pp_file_info));
}
int32_t PepperInternalFileRefBackend::ReadDirectoryEntries(
ppapi::host::ReplyMessageContext reply_context) {
if (!GetFileSystemURL().is_valid())
return PP_ERROR_FAILED;
fileapi::FileSystemOperation::FileEntryList* accumulated_file_list =
new fileapi::FileSystemOperation::FileEntryList;
GetFileSystemContext()->operation_runner()->ReadDirectory(
GetFileSystemURL(),
base::Bind(&PepperInternalFileRefBackend::ReadDirectoryComplete,
weak_factory_.GetWeakPtr(),
reply_context,
base::Owned(accumulated_file_list)));
return PP_OK_COMPLETIONPENDING;
}
void PepperInternalFileRefBackend::ReadDirectoryComplete(
ppapi::host::ReplyMessageContext context,
fileapi::FileSystemOperation::FileEntryList* accumulated_file_list,
base::File::Error error,
const fileapi::FileSystemOperation::FileEntryList& file_list,
bool has_more) {
accumulated_file_list->insert(
accumulated_file_list->end(), file_list.begin(), file_list.end());
if (has_more)
return;
context.params.set_result(ppapi::FileErrorToPepperError(error));
std::vector<ppapi::FileRefCreateInfo> infos;
std::vector<PP_FileType> file_types;
if (error == base::File::FILE_OK && fs_host_.get()) {
std::string dir_path = path_;
if (dir_path.empty() || dir_path[dir_path.size() - 1] != '/')
dir_path += '/';
for (fileapi::FileSystemOperation::FileEntryList::const_iterator it =
accumulated_file_list->begin();
it != accumulated_file_list->end();
++it) {
if (it->is_directory)
file_types.push_back(PP_FILETYPE_DIRECTORY);
else
file_types.push_back(PP_FILETYPE_REGULAR);
ppapi::FileRefCreateInfo info;
info.file_system_type = fs_type_;
info.file_system_plugin_resource = fs_host_->pp_resource();
std::string path =
dir_path + fileapi::FilePathToString(base::FilePath(it->name));
info.internal_path = path;
info.display_name = ppapi::GetNameForInternalFilePath(path);
infos.push_back(info);
}
}
host_->SendReply(
context,
PpapiPluginMsg_FileRef_ReadDirectoryEntriesReply(infos, file_types));
}
int32_t PepperInternalFileRefBackend::GetAbsolutePath(
ppapi::host::ReplyMessageContext reply_context) {
host_->SendReply(reply_context,
PpapiPluginMsg_FileRef_GetAbsolutePathReply(path_));
return PP_OK_COMPLETIONPENDING;
}
int32_t PepperInternalFileRefBackend::CanRead() const {
fileapi::FileSystemURL url = GetFileSystemURL();
if (!FileSystemURLIsValid(GetFileSystemContext().get(), url))
return PP_ERROR_FAILED;
if (!ChildProcessSecurityPolicyImpl::GetInstance()->CanReadFileSystemFile(
render_process_id_, url)) {
return PP_ERROR_NOACCESS;
}
return PP_OK;
}
int32_t PepperInternalFileRefBackend::CanWrite() const {
fileapi::FileSystemURL url = GetFileSystemURL();
if (!FileSystemURLIsValid(GetFileSystemContext().get(), url))
return PP_ERROR_FAILED;
if (!ChildProcessSecurityPolicyImpl::GetInstance()->CanWriteFileSystemFile(
render_process_id_, url)) {
return PP_ERROR_NOACCESS;
}
return PP_OK;
}
int32_t PepperInternalFileRefBackend::CanCreate() const {
fileapi::FileSystemURL url = GetFileSystemURL();
if (!FileSystemURLIsValid(GetFileSystemContext().get(), url))
return PP_ERROR_FAILED;
if (!ChildProcessSecurityPolicyImpl::GetInstance()->CanCreateFileSystemFile(
render_process_id_, url)) {
return PP_ERROR_NOACCESS;
}
return PP_OK;
}
int32_t PepperInternalFileRefBackend::CanReadWrite() const {
fileapi::FileSystemURL url = GetFileSystemURL();
if (!FileSystemURLIsValid(GetFileSystemContext().get(), url))
return PP_ERROR_FAILED;
ChildProcessSecurityPolicyImpl* policy =
ChildProcessSecurityPolicyImpl::GetInstance();
if (!policy->CanReadFileSystemFile(render_process_id_, url) ||
!policy->CanWriteFileSystemFile(render_process_id_, url)) {
return PP_ERROR_NOACCESS;
}
return PP_OK;
}
} // namespace content