blob: 7fa69bcf7753615260a112dc71c55c1b2dfe55f8 [file] [log] [blame]
// Copyright (c) 2011 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/plugins/ppapi/ppb_file_io_impl.h"
#include "base/bind.h"
#include "base/callback.h"
#include "base/file_util.h"
#include "base/file_util_proxy.h"
#include "base/message_loop_proxy.h"
#include "base/platform_file.h"
#include "base/logging.h"
#include "base/time.h"
#include "ppapi/c/ppb_file_io.h"
#include "ppapi/c/trusted/ppb_file_io_trusted.h"
#include "ppapi/c/pp_completion_callback.h"
#include "ppapi/c/pp_errors.h"
#include "ppapi/shared_impl/file_type_conversion.h"
#include "ppapi/shared_impl/time_conversion.h"
#include "ppapi/thunk/enter.h"
#include "ppapi/thunk/ppb_file_ref_api.h"
#include "webkit/plugins/ppapi/common.h"
#include "webkit/plugins/ppapi/plugin_module.h"
#include "webkit/plugins/ppapi/ppapi_plugin_instance.h"
#include "webkit/plugins/ppapi/ppb_file_ref_impl.h"
#include "webkit/plugins/ppapi/quota_file_io.h"
#include "webkit/plugins/ppapi/resource_helper.h"
using ppapi::PPTimeToTime;
using ppapi::TimeToPPTime;
using ppapi::thunk::PPB_FileRef_API;
namespace webkit {
namespace ppapi {
PPB_FileIO_Impl::PPB_FileIO_Impl(PP_Instance instance)
: ::ppapi::PPB_FileIO_Shared(instance),
file_(base::kInvalidPlatformFileValue),
ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)) {
}
PPB_FileIO_Impl::~PPB_FileIO_Impl() {
Close();
}
int32_t PPB_FileIO_Impl::OpenValidated(PP_Resource file_ref_resource,
PPB_FileRef_API* file_ref_api,
int32_t open_flags,
PP_CompletionCallback callback) {
PPB_FileRef_Impl* file_ref = static_cast<PPB_FileRef_Impl*>(file_ref_api);
int flags = 0;
if (!::ppapi::PepperFileOpenFlagsToPlatformFileFlags(open_flags, &flags))
return PP_ERROR_BADARGUMENT;
PluginDelegate* plugin_delegate = GetPluginDelegate();
if (!plugin_delegate)
return PP_ERROR_BADARGUMENT;
if (file_ref->HasValidFileSystem()) {
file_system_url_ = file_ref->GetFileSystemURL();
if (!plugin_delegate->AsyncOpenFileSystemURL(
file_system_url_, flags,
base::Bind(&PPB_FileIO_Impl::ExecutePlatformOpenFileCallback,
weak_factory_.GetWeakPtr())))
return PP_ERROR_FAILED;
} else {
if (file_system_type_ != PP_FILESYSTEMTYPE_EXTERNAL)
return PP_ERROR_FAILED;
if (!plugin_delegate->AsyncOpenFile(
file_ref->GetSystemPath(), flags,
base::Bind(&PPB_FileIO_Impl::ExecutePlatformOpenFileCallback,
weak_factory_.GetWeakPtr())))
return PP_ERROR_FAILED;
}
RegisterCallback(OPERATION_EXCLUSIVE, callback, NULL, NULL);
return PP_OK_COMPLETIONPENDING;
}
int32_t PPB_FileIO_Impl::QueryValidated(PP_FileInfo* info,
PP_CompletionCallback callback) {
PluginDelegate* plugin_delegate = GetPluginDelegate();
if (!plugin_delegate)
return PP_ERROR_FAILED;
if (!base::FileUtilProxy::GetFileInfoFromPlatformFile(
plugin_delegate->GetFileThreadMessageLoopProxy(), file_,
base::Bind(&PPB_FileIO_Impl::ExecutePlatformQueryCallback,
weak_factory_.GetWeakPtr())))
return PP_ERROR_FAILED;
RegisterCallback(OPERATION_EXCLUSIVE, callback, NULL, info);
return PP_OK_COMPLETIONPENDING;
}
int32_t PPB_FileIO_Impl::TouchValidated(PP_Time last_access_time,
PP_Time last_modified_time,
PP_CompletionCallback callback) {
PluginDelegate* plugin_delegate = GetPluginDelegate();
if (!plugin_delegate)
return PP_ERROR_FAILED;
if (!base::FileUtilProxy::Touch(
plugin_delegate->GetFileThreadMessageLoopProxy(),
file_, PPTimeToTime(last_access_time),
PPTimeToTime(last_modified_time),
base::Bind(&PPB_FileIO_Impl::ExecutePlatformGeneralCallback,
weak_factory_.GetWeakPtr())))
return PP_ERROR_FAILED;
RegisterCallback(OPERATION_EXCLUSIVE, callback, NULL, NULL);
return PP_OK_COMPLETIONPENDING;
}
int32_t PPB_FileIO_Impl::ReadValidated(int64_t offset,
char* buffer,
int32_t bytes_to_read,
PP_CompletionCallback callback) {
PluginDelegate* plugin_delegate = GetPluginDelegate();
if (!plugin_delegate)
return PP_ERROR_FAILED;
if (!base::FileUtilProxy::Read(
plugin_delegate->GetFileThreadMessageLoopProxy(), file_, offset,
bytes_to_read,
base::Bind(&PPB_FileIO_Impl::ExecutePlatformReadCallback,
weak_factory_.GetWeakPtr())))
return PP_ERROR_FAILED;
RegisterCallback(OPERATION_READ, callback, buffer, NULL);
return PP_OK_COMPLETIONPENDING;
}
int32_t PPB_FileIO_Impl::WriteValidated(int64_t offset,
const char* buffer,
int32_t bytes_to_write,
PP_CompletionCallback callback) {
PluginDelegate* plugin_delegate = GetPluginDelegate();
if (!plugin_delegate)
return PP_ERROR_FAILED;
if (quota_file_io_.get()) {
if (!quota_file_io_->Write(
offset, buffer, bytes_to_write,
base::Bind(&PPB_FileIO_Impl::ExecutePlatformWriteCallback,
weak_factory_.GetWeakPtr())))
return PP_ERROR_FAILED;
} else {
if (!base::FileUtilProxy::Write(
plugin_delegate->GetFileThreadMessageLoopProxy(), file_, offset,
buffer, bytes_to_write,
base::Bind(&PPB_FileIO_Impl::ExecutePlatformWriteCallback,
weak_factory_.GetWeakPtr())))
return PP_ERROR_FAILED;
}
RegisterCallback(OPERATION_WRITE, callback, NULL, NULL);
return PP_OK_COMPLETIONPENDING;
}
int32_t PPB_FileIO_Impl::SetLengthValidated(int64_t length,
PP_CompletionCallback callback) {
PluginDelegate* plugin_delegate = GetPluginDelegate();
if (!plugin_delegate)
return PP_ERROR_FAILED;
if (quota_file_io_.get()) {
if (!quota_file_io_->SetLength(
length,
base::Bind(&PPB_FileIO_Impl::ExecutePlatformGeneralCallback,
weak_factory_.GetWeakPtr())))
return PP_ERROR_FAILED;
} else {
if (!base::FileUtilProxy::Truncate(
plugin_delegate->GetFileThreadMessageLoopProxy(), file_, length,
base::Bind(&PPB_FileIO_Impl::ExecutePlatformGeneralCallback,
weak_factory_.GetWeakPtr())))
return PP_ERROR_FAILED;
}
RegisterCallback(OPERATION_EXCLUSIVE, callback, NULL, NULL);
return PP_OK_COMPLETIONPENDING;
}
int32_t PPB_FileIO_Impl::FlushValidated(PP_CompletionCallback callback) {
PluginDelegate* plugin_delegate = GetPluginDelegate();
if (!plugin_delegate)
return PP_ERROR_FAILED;
if (!base::FileUtilProxy::Flush(
plugin_delegate->GetFileThreadMessageLoopProxy(), file_,
base::Bind(&PPB_FileIO_Impl::ExecutePlatformGeneralCallback,
weak_factory_.GetWeakPtr())))
return PP_ERROR_FAILED;
RegisterCallback(OPERATION_EXCLUSIVE, callback, NULL, NULL);
return PP_OK_COMPLETIONPENDING;
}
void PPB_FileIO_Impl::Close() {
PluginDelegate* plugin_delegate = GetPluginDelegate();
if (file_ != base::kInvalidPlatformFileValue && plugin_delegate) {
base::FileUtilProxy::Close(
plugin_delegate->GetFileThreadMessageLoopProxy(), file_,
base::FileUtilProxy::StatusCallback());
file_ = base::kInvalidPlatformFileValue;
quota_file_io_.reset();
}
}
int32_t PPB_FileIO_Impl::GetOSFileDescriptor() {
#if defined(OS_POSIX)
return file_;
#elif defined(OS_WIN)
return reinterpret_cast<uintptr_t>(file_);
#else
#error "Platform not supported."
#endif
}
int32_t PPB_FileIO_Impl::WillWrite(int64_t offset,
int32_t bytes_to_write,
PP_CompletionCallback callback) {
int32_t rv = CommonCallValidation(true, OPERATION_EXCLUSIVE, callback);
if (rv != PP_OK)
return rv;
if (!quota_file_io_.get())
return PP_OK;
if (!quota_file_io_->WillWrite(
offset, bytes_to_write,
base::Bind(&PPB_FileIO_Impl::ExecutePlatformWillWriteCallback,
weak_factory_.GetWeakPtr())))
return PP_ERROR_FAILED;
RegisterCallback(OPERATION_EXCLUSIVE, callback, NULL, NULL);
return PP_OK_COMPLETIONPENDING;
}
int32_t PPB_FileIO_Impl::WillSetLength(int64_t length,
PP_CompletionCallback callback) {
int32_t rv = CommonCallValidation(true, OPERATION_EXCLUSIVE, callback);
if (rv != PP_OK)
return rv;
if (!quota_file_io_.get())
return PP_OK;
if (!quota_file_io_->WillSetLength(
length,
base::Bind(&PPB_FileIO_Impl::ExecutePlatformGeneralCallback,
weak_factory_.GetWeakPtr())))
return PP_ERROR_FAILED;
RegisterCallback(OPERATION_EXCLUSIVE, callback, NULL, NULL);
return PP_OK_COMPLETIONPENDING;
}
PluginDelegate* PPB_FileIO_Impl::GetPluginDelegate() {
return ResourceHelper::GetPluginDelegate(this);
}
void PPB_FileIO_Impl::ExecutePlatformGeneralCallback(
base::PlatformFileError error_code) {
ExecuteGeneralCallback(::ppapi::PlatformFileErrorToPepperError(error_code));
}
void PPB_FileIO_Impl::ExecutePlatformOpenFileCallback(
base::PlatformFileError error_code,
base::PassPlatformFile file) {
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(
pp_instance(), file_, file_system_url_, file_system_type_));
}
ExecuteOpenFileCallback(::ppapi::PlatformFileErrorToPepperError(error_code));
}
void PPB_FileIO_Impl::ExecutePlatformQueryCallback(
base::PlatformFileError error_code,
const base::PlatformFileInfo& file_info) {
PP_FileInfo pp_info;
pp_info.size = file_info.size;
pp_info.creation_time = TimeToPPTime(file_info.creation_time);
pp_info.last_access_time = TimeToPPTime(file_info.last_accessed);
pp_info.last_modified_time = TimeToPPTime(file_info.last_modified);
pp_info.system_type = file_system_type_;
if (file_info.is_directory)
pp_info.type = PP_FILETYPE_DIRECTORY;
else
pp_info.type = PP_FILETYPE_REGULAR;
ExecuteQueryCallback(::ppapi::PlatformFileErrorToPepperError(error_code),
pp_info);
}
void PPB_FileIO_Impl::ExecutePlatformReadCallback(
base::PlatformFileError error_code,
const char* data, int bytes_read) {
// Map the error code, OK getting mapped to the # of bytes read.
int32_t pp_result = ::ppapi::PlatformFileErrorToPepperError(error_code);
pp_result = pp_result == PP_OK ? bytes_read : pp_result;
ExecuteReadCallback(pp_result, data);
}
void PPB_FileIO_Impl::ExecutePlatformWriteCallback(
base::PlatformFileError error_code,
int bytes_written) {
int32_t pp_result = ::ppapi::PlatformFileErrorToPepperError(error_code);
ExecuteGeneralCallback(pp_result == PP_OK ? bytes_written : pp_result);
}
void PPB_FileIO_Impl::ExecutePlatformWillWriteCallback(
base::PlatformFileError error_code,
int bytes_written) {
if (pending_op_ != OPERATION_EXCLUSIVE || callbacks_.empty()) {
NOTREACHED();
return;
}
if (error_code != base::PLATFORM_FILE_OK) {
RunAndRemoveFirstPendingCallback(
::ppapi::PlatformFileErrorToPepperError(error_code));
} else {
RunAndRemoveFirstPendingCallback(bytes_written);
}
}
} // namespace ppapi
} // namespace webkit