// Copyright 2014 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 "ppapi/proxy/file_mapping_resource.h" #include "base/bind.h" #include "base/numerics/safe_conversions.h" #include "base/task_runner_util.h" #include "ppapi/c/pp_errors.h" #include "ppapi/shared_impl/tracked_callback.h" #include "ppapi/shared_impl/var.h" #include "ppapi/thunk/enter.h" #include "ppapi/thunk/ppb_file_io_api.h" namespace ppapi { namespace proxy { FileMappingResource::FileMappingResource(Connection connection, PP_Instance instance) : PluginResource(connection, instance) { } FileMappingResource::~FileMappingResource() { } thunk::PPB_FileMapping_API* FileMappingResource::AsPPB_FileMapping_API() { return this; } int32_t FileMappingResource::Map(PP_Instance /* instance */, PP_Resource file_io, int64_t length, uint32_t protection, uint32_t flags, int64_t offset, void** address, scoped_refptr callback) { thunk::EnterResourceNoLock enter(file_io, true); if (enter.failed()) return PP_ERROR_BADARGUMENT; FileIOResource* file_io_resource = static_cast(enter.object()); scoped_refptr file_holder = file_io_resource->file_holder(); if (!FileIOResource::FileHolder::IsValid(file_holder)) return PP_ERROR_FAILED; if (length < 0 || offset < 0 || !base::IsValueInRangeForNumericType(offset)) { return PP_ERROR_BADARGUMENT; } if (!base::IsValueInRangeForNumericType(length)) { return PP_ERROR_NOMEMORY; } // Ensure any bits we don't recognize are zero. if (protection & ~(PP_FILEMAPPROTECTION_READ | PP_FILEMAPPROTECTION_WRITE)) { return PP_ERROR_BADARGUMENT; } if (flags & ~(PP_FILEMAPFLAG_SHARED | PP_FILEMAPFLAG_PRIVATE | PP_FILEMAPFLAG_FIXED)) { return PP_ERROR_BADARGUMENT; } // Ensure at least one of SHARED and PRIVATE is set. if (!(flags & (PP_FILEMAPFLAG_SHARED | PP_FILEMAPFLAG_PRIVATE))) return PP_ERROR_BADARGUMENT; // Ensure at most one of SHARED and PRIVATE is set. if ((flags & PP_FILEMAPFLAG_SHARED) && (flags & PP_FILEMAPFLAG_PRIVATE)) { return PP_ERROR_BADARGUMENT; } if (!address) return PP_ERROR_BADARGUMENT; base::Callback map_cb( base::Bind(&FileMappingResource::DoMapBlocking, file_holder, *address, length, protection, flags, offset)); if (callback->is_blocking()) { // The plugin could release its reference to this instance when we release // the proxy lock below. scoped_refptr protect(this); MapResult map_result; { // Release the proxy lock while making a potentially slow file call. ProxyAutoUnlock unlock; map_result = map_cb.Run(); } OnMapCompleted(address, length, callback, map_result); return map_result.result; } else { base::PostTaskAndReplyWithResult( PpapiGlobals::Get()->GetFileTaskRunner(), FROM_HERE, map_cb, RunWhileLocked(Bind(&FileMappingResource::OnMapCompleted, this, base::Unretained(address), length, callback))); return PP_OK_COMPLETIONPENDING; } } int32_t FileMappingResource::Unmap(PP_Instance /* instance */, const void* address, int64_t length, scoped_refptr callback) { if (!address) return PP_ERROR_BADARGUMENT; if (!base::IsValueInRangeForNumericType(length)) return PP_ERROR_BADARGUMENT; base::Callback unmap_cb( base::Bind(&FileMappingResource::DoUnmapBlocking, address, length)); if (callback->is_blocking()) { // Release the proxy lock while making a potentially slow file call. ProxyAutoUnlock unlock; return unmap_cb.Run(); } else { base::PostTaskAndReplyWithResult( PpapiGlobals::Get()->GetFileTaskRunner(), FROM_HERE, unmap_cb, RunWhileLocked(Bind(&TrackedCallback::Run, callback))); return PP_OK_COMPLETIONPENDING; } } int64_t FileMappingResource::GetMapPageSize(PP_Instance /* instance */) { return DoGetMapPageSize(); } void FileMappingResource::OnMapCompleted( void** mapped_address_out_param, int64_t length, scoped_refptr callback, const MapResult& map_result) { if (callback->aborted()) { if (map_result.result == PP_OK) { // If the Map operation was successful, we need to Unmap to avoid leaks. // The plugin won't get the address, so doesn't have a chance to do the // Unmap. PpapiGlobals::Get()->GetFileTaskRunner()->PostTask( FROM_HERE, base::Bind(base::IgnoreResult(&FileMappingResource::DoUnmapBlocking), map_result.address, length)); } return; } if (map_result.result == PP_OK) *mapped_address_out_param = map_result.address; if (!callback->is_blocking()) callback->Run(map_result.result); } } // namespace proxy } // namespace ppapi