blob: 5a6d40ce5c9193ad6aeec494bc0ee45217bcaed6 [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 "content/renderer/pepper/pepper_file_io_host.h"
#include "base/bind.h"
#include "base/callback.h"
#include "base/callback_helpers.h"
#include "base/command_line.h"
#include "base/files/file_util_proxy.h"
#include "content/child/child_thread.h"
#include "content/child/fileapi/file_system_dispatcher.h"
#include "content/child/quota_dispatcher.h"
#include "content/common/fileapi/file_system_messages.h"
#include "content/common/view_messages.h"
#include "content/public/common/content_client.h"
#include "content/public/renderer/content_renderer_client.h"
#include "content/renderer/pepper/host_globals.h"
#include "content/renderer/pepper/pepper_plugin_instance_impl.h"
#include "content/renderer/pepper/ppb_file_ref_impl.h"
#include "content/renderer/pepper/quota_file_io.h"
#include "content/renderer/render_thread_impl.h"
#include "ppapi/c/pp_errors.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_type_conversion.h"
#include "ppapi/shared_impl/time_conversion.h"
#include "ppapi/thunk/enter.h"
#include "third_party/WebKit/public/web/WebPluginContainer.h"
namespace content {
using ppapi::FileIOStateManager;
using ppapi::PPTimeToTime;
using ppapi::host::ReplyMessageContext;
using ppapi::thunk::EnterResourceNoLock;
using ppapi::thunk::PPB_FileRef_API;
namespace {
// The maximum size we'll support reading in one chunk. The renderer process
// must allocate a buffer sized according to the request of the plugin. To
// keep things from getting out of control, we cap the read size to this value.
// This should generally be OK since the API specifies that it may perform a
// partial read.
static const int32_t kMaxReadSize = 32 * 1024 * 1024; // 32MB
typedef base::Callback<void (base::PlatformFileError)> PlatformGeneralCallback;
int32_t ErrorOrByteNumber(int32_t pp_error, int32_t byte_number) {
// On the plugin side, some callbacks expect a parameter that means different
// things depending on whether is negative or not. We translate for those
// callbacks here.
return pp_error == PP_OK ? byte_number : pp_error;
}
class QuotaCallbackTranslator : public QuotaDispatcher::Callback {
public:
typedef QuotaFileIO::Delegate::AvailableSpaceCallback PluginCallback;
explicit QuotaCallbackTranslator(const PluginCallback& cb) : callback_(cb) {}
virtual void DidQueryStorageUsageAndQuota(int64 usage, int64 quota) OVERRIDE {
callback_.Run(std::max(static_cast<int64>(0), quota - usage));
}
virtual void DidGrantStorageQuota(int64 granted_quota) OVERRIDE {
NOTREACHED();
}
virtual void DidFail(quota::QuotaStatusCode error) OVERRIDE {
callback_.Run(0);
}
private:
PluginCallback callback_;
};
class QuotaFileIODelegate : public QuotaFileIO::Delegate {
public:
QuotaFileIODelegate() {}
virtual ~QuotaFileIODelegate() {}
virtual void QueryAvailableSpace(
const GURL& origin,
quota::StorageType type,
const AvailableSpaceCallback& callback) OVERRIDE {
ChildThread::current()->quota_dispatcher()->QueryStorageUsageAndQuota(
origin, type, new QuotaCallbackTranslator(callback));
}
virtual void WillUpdateFile(const GURL& file_path) OVERRIDE {
ChildThread::current()->Send(new FileSystemHostMsg_WillUpdate(file_path));
}
virtual void DidUpdateFile(const GURL& file_path, int64_t delta) OVERRIDE {
ChildThread::current()->Send(new FileSystemHostMsg_DidUpdate(
file_path, delta));
}
virtual scoped_refptr<base::MessageLoopProxy>
GetFileThreadMessageLoopProxy() OVERRIDE {
return RenderThreadImpl::current()->GetFileThreadMessageLoopProxy();
}
};
typedef base::Callback<
void (base::PlatformFileError error,
base::PassPlatformFile file,
quota::QuotaLimitType quota_policy,
const PepperFileIOHost::NotifyCloseFileCallback& close_file_callback)>
AsyncOpenFileSystemURLCallback;
void DoNotifyCloseFile(int file_open_id, base::PlatformFileError error) {
ChildThread::current()->file_system_dispatcher()->NotifyCloseFile(
file_open_id);
}
void DidOpenFileSystemURL(const AsyncOpenFileSystemURLCallback& callback,
base::PlatformFile file,
int file_open_id,
quota::QuotaLimitType quota_policy) {
callback.Run(base::PLATFORM_FILE_OK,
base::PassPlatformFile(&file),
quota_policy,
base::Bind(&DoNotifyCloseFile, file_open_id));
// Make sure we won't leak file handle if the requester has died.
if (file != base::kInvalidPlatformFileValue) {
base::FileUtilProxy::Close(
RenderThreadImpl::current()->GetFileThreadMessageLoopProxy().get(),
file,
base::Bind(&DoNotifyCloseFile, file_open_id));
}
}
void DidFailOpenFileSystemURL(const AsyncOpenFileSystemURLCallback& callback,
base::PlatformFileError error_code) {
base::PlatformFile invalid_file = base::kInvalidPlatformFileValue;
callback.Run(error_code,
base::PassPlatformFile(&invalid_file),
quota::kQuotaLimitTypeUnknown,
PepperFileIOHost::NotifyCloseFileCallback());
}
} // namespace
PepperFileIOHost::PepperFileIOHost(RendererPpapiHost* host,
PP_Instance instance,
PP_Resource resource)
: ResourceHost(host->GetPpapiHost(), instance, resource),
file_(base::kInvalidPlatformFileValue),
file_system_type_(PP_FILESYSTEMTYPE_INVALID),
quota_policy_(quota::kQuotaLimitTypeUnknown),
is_running_in_process_(host->IsRunningInProcess()),
open_flags_(0),
weak_factory_(this),
routing_id_(RenderThreadImpl::current()->GenerateRoutingID()) {
ChildThread::current()->AddRoute(routing_id_, this);
}
PepperFileIOHost::~PepperFileIOHost() {
OnHostMsgClose(NULL);
ChildThread::current()->RemoveRoute(routing_id_);
}
int32_t PepperFileIOHost::OnResourceMessageReceived(
const IPC::Message& msg,
ppapi::host::HostMessageContext* context) {
IPC_BEGIN_MESSAGE_MAP(PepperFileIOHost, msg)
PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_FileIO_Open,
OnHostMsgOpen)
PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(PpapiHostMsg_FileIO_Query,
OnHostMsgQuery)
PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_FileIO_Touch,
OnHostMsgTouch)
PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_FileIO_Read,
OnHostMsgRead)
PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_FileIO_Write,
OnHostMsgWrite)
PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_FileIO_SetLength,
OnHostMsgSetLength)
PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(PpapiHostMsg_FileIO_Flush,
OnHostMsgFlush)
PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(PpapiHostMsg_FileIO_Close,
OnHostMsgClose)
PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_FileIO_WillWrite,
OnHostMsgWillWrite)
PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_FileIO_WillSetLength,
OnHostMsgWillSetLength)
PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(PpapiHostMsg_FileIO_GetOSFileDescriptor,
OnHostMsgGetOSFileDescriptor)
PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(PpapiHostMsg_FileIO_RequestOSFileHandle,
OnHostMsgRequestOSFileHandle)
IPC_END_MESSAGE_MAP()
return PP_ERROR_FAILED;
}
bool PepperFileIOHost::OnMessageReceived(const IPC::Message& msg) {
bool handled = true;
IPC_BEGIN_MESSAGE_MAP(PepperFileIOHost, msg)
IPC_MESSAGE_HANDLER(ViewMsg_AsyncOpenPepperFile_ACK, OnAsyncFileOpened)
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
return handled;
}
void PepperFileIOHost::OnAsyncFileOpened(
base::PlatformFileError error_code,
IPC::PlatformFileForTransit file_for_transit,
int message_id) {
AsyncOpenFileCallback* callback =
pending_async_open_files_.Lookup(message_id);
DCHECK(callback);
pending_async_open_files_.Remove(message_id);
base::PlatformFile file =
IPC::PlatformFileForTransitToPlatformFile(file_for_transit);
callback->Run(error_code, base::PassPlatformFile(&file));
// Make sure we won't leak file handle if the requester has died.
if (file != base::kInvalidPlatformFileValue) {
base::FileUtilProxy::Close(
RenderThreadImpl::current()->GetFileThreadMessageLoopProxy().get(),
file,
base::FileUtilProxy::StatusCallback());
}
delete callback;
}
int32_t PepperFileIOHost::OnHostMsgOpen(
ppapi::host::HostMessageContext* context,
PP_Resource file_ref_resource,
int32_t open_flags) {
int32_t rv = state_manager_.CheckOperationState(
FileIOStateManager::OPERATION_EXCLUSIVE, false);
if (rv != PP_OK)
return rv;
// TODO(tommycli): Eventually just pass the Pepper flags straight to the
// FileSystemDispatcher so it can handle doing the security check.
int platform_file_flags = 0;
open_flags_ = open_flags;
if (!::ppapi::PepperFileOpenFlagsToPlatformFileFlags(open_flags,
&platform_file_flags)) {
return PP_ERROR_BADARGUMENT;
}
EnterResourceNoLock<PPB_FileRef_API> enter(file_ref_resource, true);
if (enter.failed())
return PP_ERROR_BADRESOURCE;
PPB_FileRef_API* file_ref_api = enter.object();
PP_FileSystemType type = file_ref_api->GetFileSystemType();
if (type != PP_FILESYSTEMTYPE_LOCALPERSISTENT &&
type != PP_FILESYSTEMTYPE_LOCALTEMPORARY &&
type != PP_FILESYSTEMTYPE_EXTERNAL &&
type != PP_FILESYSTEMTYPE_ISOLATED)
return PP_ERROR_FAILED;
file_system_type_ = type;
PPB_FileRef_Impl* file_ref = static_cast<PPB_FileRef_Impl*>(file_ref_api);
if (file_ref->HasValidFileSystem()) {
file_system_url_ = file_ref->GetFileSystemURL();
FileSystemDispatcher* file_system_dispatcher =
ChildThread::current()->file_system_dispatcher();
AsyncOpenFileSystemURLCallback callback = base::Bind(
&PepperFileIOHost::ExecutePlatformOpenFileSystemURLCallback,
weak_factory_.GetWeakPtr(),
context->MakeReplyMessageContext());
file_system_dispatcher->OpenFile(
file_system_url_, platform_file_flags,
base::Bind(&DidOpenFileSystemURL, callback),
base::Bind(&DidFailOpenFileSystemURL, callback));
} else {
if (file_system_type_ != PP_FILESYSTEMTYPE_EXTERNAL)
return PP_ERROR_FAILED;
int message_id = pending_async_open_files_.Add(new AsyncOpenFileCallback(
base::Bind(&PepperFileIOHost::ExecutePlatformOpenFileCallback,
weak_factory_.GetWeakPtr(),
context->MakeReplyMessageContext())));
RenderThreadImpl::current()->Send(new ViewHostMsg_AsyncOpenPepperFile(
routing_id_, file_ref->GetSystemPath(), open_flags, message_id));
}
state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_EXCLUSIVE);
return PP_OK_COMPLETIONPENDING;
}
int32_t PepperFileIOHost::OnHostMsgQuery(
ppapi::host::HostMessageContext* context) {
int32_t rv = state_manager_.CheckOperationState(
FileIOStateManager::OPERATION_EXCLUSIVE, true);
if (rv != PP_OK)
return rv;
if (!base::FileUtilProxy::GetFileInfoFromPlatformFile(
RenderThreadImpl::current()->GetFileThreadMessageLoopProxy().get(),
file_,
base::Bind(&PepperFileIOHost::ExecutePlatformQueryCallback,
weak_factory_.GetWeakPtr(),
context->MakeReplyMessageContext())))
return PP_ERROR_FAILED;
state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_EXCLUSIVE);
return PP_OK_COMPLETIONPENDING;
}
int32_t PepperFileIOHost::OnHostMsgTouch(
ppapi::host::HostMessageContext* context,
PP_Time last_access_time,
PP_Time last_modified_time) {
int32_t rv = state_manager_.CheckOperationState(
FileIOStateManager::OPERATION_EXCLUSIVE, true);
if (rv != PP_OK)
return rv;
if (file_system_type_ != PP_FILESYSTEMTYPE_EXTERNAL) {
FileSystemDispatcher* file_system_dispatcher =
ChildThread::current()->file_system_dispatcher();
file_system_dispatcher->TouchFile(
file_system_url_,
PPTimeToTime(last_access_time),
PPTimeToTime(last_modified_time),
base::Bind(&PepperFileIOHost::ExecutePlatformGeneralCallback,
weak_factory_.GetWeakPtr(),
context->MakeReplyMessageContext()));
state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_EXCLUSIVE);
return PP_OK_COMPLETIONPENDING;
}
// TODO(nhiroki): fix a failure of FileIO.Touch for an external filesystem on
// Mac and Linux due to sandbox restrictions (http://crbug.com/101128).
if (!base::FileUtilProxy::Touch(
RenderThreadImpl::current()->GetFileThreadMessageLoopProxy().get(),
file_,
PPTimeToTime(last_access_time),
PPTimeToTime(last_modified_time),
base::Bind(&PepperFileIOHost::ExecutePlatformGeneralCallback,
weak_factory_.GetWeakPtr(),
context->MakeReplyMessageContext())))
return PP_ERROR_FAILED;
state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_EXCLUSIVE);
return PP_OK_COMPLETIONPENDING;
}
int32_t PepperFileIOHost::OnHostMsgRead(
ppapi::host::HostMessageContext* context,
int64_t offset,
int32_t max_read_length) {
int32_t rv = state_manager_.CheckOperationState(
FileIOStateManager::OPERATION_READ, true);
if (rv != PP_OK)
return rv;
// Validate max_read_length before allocating below. This value is coming from
// the untrusted plugin.
if (max_read_length < 0) {
ReplyMessageContext reply_context = context->MakeReplyMessageContext();
reply_context.params.set_result(PP_ERROR_FAILED);
host()->SendReply(reply_context,
PpapiPluginMsg_FileIO_ReadReply(std::string()));
return PP_OK_COMPLETIONPENDING;
}
if (!base::FileUtilProxy::Read(
RenderThreadImpl::current()->GetFileThreadMessageLoopProxy().get(),
file_,
offset,
max_read_length,
base::Bind(&PepperFileIOHost::ExecutePlatformReadCallback,
weak_factory_.GetWeakPtr(),
context->MakeReplyMessageContext())))
return PP_ERROR_FAILED;
state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_READ);
return PP_OK_COMPLETIONPENDING;
}
int32_t PepperFileIOHost::OnHostMsgWrite(
ppapi::host::HostMessageContext* context,
int64_t offset,
const std::string& buffer) {
int32_t rv = state_manager_.CheckOperationState(
FileIOStateManager::OPERATION_WRITE, true);
if (rv != PP_OK)
return rv;
if (quota_file_io_) {
if (!quota_file_io_->Write(
offset, buffer.c_str(), buffer.size(),
base::Bind(&PepperFileIOHost::ExecutePlatformWriteCallback,
weak_factory_.GetWeakPtr(),
context->MakeReplyMessageContext())))
return PP_ERROR_FAILED;
} else {
if (!base::FileUtilProxy::Write(
RenderThreadImpl::current()->GetFileThreadMessageLoopProxy().get(),
file_,
offset,
buffer.c_str(),
buffer.size(),
base::Bind(&PepperFileIOHost::ExecutePlatformWriteCallback,
weak_factory_.GetWeakPtr(),
context->MakeReplyMessageContext())))
return PP_ERROR_FAILED;
}
state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_WRITE);
return PP_OK_COMPLETIONPENDING;
}
int32_t PepperFileIOHost::OnHostMsgSetLength(
ppapi::host::HostMessageContext* context,
int64_t length) {
int32_t rv = state_manager_.CheckOperationState(
FileIOStateManager::OPERATION_EXCLUSIVE, true);
if (rv != PP_OK)
return rv;
if (file_system_type_ != PP_FILESYSTEMTYPE_EXTERNAL) {
FileSystemDispatcher* file_system_dispatcher =
ChildThread::current()->file_system_dispatcher();
file_system_dispatcher->Truncate(
file_system_url_, length, NULL,
base::Bind(&PepperFileIOHost::ExecutePlatformGeneralCallback,
weak_factory_.GetWeakPtr(),
context->MakeReplyMessageContext()));
} else {
// TODO(nhiroki): fix a failure of FileIO.SetLength for an external
// filesystem on Mac due to sandbox restrictions (http://crbug.com/156077).
if (!base::FileUtilProxy::Truncate(
RenderThreadImpl::current()->GetFileThreadMessageLoopProxy().get(),
file_,
length,
base::Bind(&PepperFileIOHost::ExecutePlatformGeneralCallback,
weak_factory_.GetWeakPtr(),
context->MakeReplyMessageContext())))
return PP_ERROR_FAILED;
}
state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_EXCLUSIVE);
return PP_OK_COMPLETIONPENDING;
}
int32_t PepperFileIOHost::OnHostMsgFlush(
ppapi::host::HostMessageContext* context) {
int32_t rv = state_manager_.CheckOperationState(
FileIOStateManager::OPERATION_EXCLUSIVE, true);
if (rv != PP_OK)
return rv;
if (!base::FileUtilProxy::Flush(
RenderThreadImpl::current()->GetFileThreadMessageLoopProxy().get(),
file_,
base::Bind(&PepperFileIOHost::ExecutePlatformGeneralCallback,
weak_factory_.GetWeakPtr(),
context->MakeReplyMessageContext())))
return PP_ERROR_FAILED;
state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_EXCLUSIVE);
return PP_OK_COMPLETIONPENDING;
}
int32_t PepperFileIOHost::OnHostMsgClose(
ppapi::host::HostMessageContext* context) {
if (file_ != base::kInvalidPlatformFileValue) {
base::FileUtilProxy::Close(
RenderThreadImpl::current()->GetFileThreadMessageLoopProxy().get(),
file_,
base::ResetAndReturn(&notify_close_file_callback_));
file_ = base::kInvalidPlatformFileValue;
quota_file_io_.reset();
}
return PP_OK;
}
int32_t PepperFileIOHost::OnHostMsgWillWrite(
ppapi::host::HostMessageContext* context,
int64_t offset,
int32_t bytes_to_write) {
int32_t rv = state_manager_.CheckOperationState(
FileIOStateManager::OPERATION_EXCLUSIVE, true);
if (rv != PP_OK)
return rv;
if (!quota_file_io_)
return PP_OK;
if (!quota_file_io_->WillWrite(
offset, bytes_to_write,
base::Bind(&PepperFileIOHost::ExecutePlatformWriteCallback,
weak_factory_.GetWeakPtr(),
context->MakeReplyMessageContext())))
return PP_ERROR_FAILED;
state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_EXCLUSIVE);
return PP_OK_COMPLETIONPENDING;
}
int32_t PepperFileIOHost::OnHostMsgWillSetLength(
ppapi::host::HostMessageContext* context,
int64_t length) {
int32_t rv = state_manager_.CheckOperationState(
FileIOStateManager::OPERATION_EXCLUSIVE, true);
if (rv != PP_OK)
return rv;
if (!quota_file_io_)
return PP_OK;
if (!quota_file_io_->WillSetLength(
length,
base::Bind(&PepperFileIOHost::ExecutePlatformGeneralCallback,
weak_factory_.GetWeakPtr(),
context->MakeReplyMessageContext())))
return PP_ERROR_FAILED;
state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_EXCLUSIVE);
return PP_OK_COMPLETIONPENDING;
}
int32_t PepperFileIOHost::OnHostMsgRequestOSFileHandle(
ppapi::host::HostMessageContext* context) {
if (!is_running_in_process_ &&
quota_policy_ != quota::kQuotaLimitTypeUnlimited)
return PP_ERROR_FAILED;
RendererPpapiHost* renderer_ppapi_host =
RendererPpapiHost::GetForPPInstance(pp_instance());
// Whitelist to make it privately accessible.
if (!GetContentClient()->renderer()->IsPluginAllowedToCallRequestOSFileHandle(
renderer_ppapi_host->GetContainerForInstance(pp_instance())))
return PP_ERROR_NOACCESS;
IPC::PlatformFileForTransit file =
renderer_ppapi_host->ShareHandleWithRemote(file_, false);
if (file == IPC::InvalidPlatformFileForTransit())
return PP_ERROR_FAILED;
ppapi::host::ReplyMessageContext reply_context =
context->MakeReplyMessageContext();
ppapi::proxy::SerializedHandle file_handle;
file_handle.set_file_handle(file, open_flags_);
reply_context.params.AppendHandle(file_handle);
host()->SendReply(reply_context,
PpapiPluginMsg_FileIO_RequestOSFileHandleReply());
return PP_OK_COMPLETIONPENDING;
}
int32_t PepperFileIOHost::OnHostMsgGetOSFileDescriptor(
ppapi::host::HostMessageContext* context) {
if (!is_running_in_process_)
return PP_ERROR_FAILED;
int32_t fd =
#if defined(OS_POSIX)
file_;
#elif defined(OS_WIN)
reinterpret_cast<uintptr_t>(file_);
#else
-1;
#endif
host()->SendReply(context->MakeReplyMessageContext(),
PpapiPluginMsg_FileIO_GetOSFileDescriptorReply(fd));
return PP_OK_COMPLETIONPENDING;
}
void PepperFileIOHost::ExecutePlatformGeneralCallback(
ppapi::host::ReplyMessageContext reply_context,
base::PlatformFileError error_code) {
reply_context.params.set_result(
::ppapi::PlatformFileErrorToPepperError(error_code));
host()->SendReply(reply_context, PpapiPluginMsg_FileIO_GeneralReply());
state_manager_.SetOperationFinished();
}
void PepperFileIOHost::ExecutePlatformOpenFileCallback(
ppapi::host::ReplyMessageContext reply_context,
base::PlatformFileError error_code,
base::PassPlatformFile file) {
int32_t pp_error = ::ppapi::PlatformFileErrorToPepperError(error_code);
if (pp_error == PP_OK)
state_manager_.SetOpenSucceed();
DCHECK(file_ == base::kInvalidPlatformFileValue);
file_ = file.ReleaseValue();
DCHECK(!quota_file_io_.get());
if (file_ != base::kInvalidPlatformFileValue &&
(file_system_type_ == PP_FILESYSTEMTYPE_LOCALTEMPORARY ||
file_system_type_ == PP_FILESYSTEMTYPE_LOCALPERSISTENT)) {
quota_file_io_.reset(new QuotaFileIO(
new QuotaFileIODelegate, file_, file_system_url_, file_system_type_));
}
reply_context.params.set_result(pp_error);
host()->SendReply(reply_context, PpapiPluginMsg_FileIO_OpenReply());
state_manager_.SetOperationFinished();
}
void PepperFileIOHost::ExecutePlatformOpenFileSystemURLCallback(
ppapi::host::ReplyMessageContext reply_context,
base::PlatformFileError error_code,
base::PassPlatformFile file,
quota::QuotaLimitType quota_policy,
const PepperFileIOHost::NotifyCloseFileCallback& callback) {
if (error_code == base::PLATFORM_FILE_OK)
notify_close_file_callback_ = callback;
quota_policy_ = quota_policy;
ExecutePlatformOpenFileCallback(reply_context, error_code, file);
}
void PepperFileIOHost::ExecutePlatformQueryCallback(
ppapi::host::ReplyMessageContext reply_context,
base::PlatformFileError error_code,
const base::PlatformFileInfo& file_info) {
PP_FileInfo pp_info;
ppapi::PlatformFileInfoToPepperFileInfo(file_info, file_system_type_,
&pp_info);
int32_t pp_error = ::ppapi::PlatformFileErrorToPepperError(error_code);
reply_context.params.set_result(pp_error);
host()->SendReply(reply_context,
PpapiPluginMsg_FileIO_QueryReply(pp_info));
state_manager_.SetOperationFinished();
}
void PepperFileIOHost::ExecutePlatformReadCallback(
ppapi::host::ReplyMessageContext reply_context,
base::PlatformFileError error_code,
const char* data, int bytes_read) {
int32_t pp_error = ::ppapi::PlatformFileErrorToPepperError(error_code);
// Only send the amount of data in the string that was actually read.
std::string buffer;
if (pp_error == PP_OK)
buffer.append(data, bytes_read);
reply_context.params.set_result(ErrorOrByteNumber(pp_error, bytes_read));
host()->SendReply(reply_context, PpapiPluginMsg_FileIO_ReadReply(buffer));
state_manager_.SetOperationFinished();
}
void PepperFileIOHost::ExecutePlatformWriteCallback(
ppapi::host::ReplyMessageContext reply_context,
base::PlatformFileError error_code,
int bytes_written) {
// On the plugin side, the callback expects a parameter with different meaning
// depends on whether is negative or not. It is the result here. We translate
// for the callback.
int32_t pp_error = ::ppapi::PlatformFileErrorToPepperError(error_code);
reply_context.params.set_result(ErrorOrByteNumber(pp_error, bytes_written));
host()->SendReply(reply_context, PpapiPluginMsg_FileIO_GeneralReply());
state_manager_.SetOperationFinished();
}
} // namespace content