15d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved.
25d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// found in the LICENSE file.
45d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
55d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "ppapi/proxy/file_mapping_resource.h"
65d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
75d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/bind.h"
85d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/numerics/safe_conversions.h"
95d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/task_runner_util.h"
105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "ppapi/c/pp_errors.h"
115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "ppapi/shared_impl/tracked_callback.h"
125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "ppapi/shared_impl/var.h"
135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "ppapi/thunk/enter.h"
145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "ppapi/thunk/ppb_file_io_api.h"
155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)namespace ppapi {
175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)namespace proxy {
185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)FileMappingResource::FileMappingResource(Connection connection,
205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                         PP_Instance instance)
215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    : PluginResource(connection, instance) {
225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)FileMappingResource::~FileMappingResource() {
255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)thunk::PPB_FileMapping_API* FileMappingResource::AsPPB_FileMapping_API() {
285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return this;
295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)int32_t FileMappingResource::Map(PP_Instance /* instance */,
325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                 PP_Resource file_io,
335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                 int64_t length,
345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                 uint32_t protection,
355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                 uint32_t flags,
365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                 int64_t offset,
375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                 void** address,
385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                 scoped_refptr<TrackedCallback> callback) {
395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  thunk::EnterResourceNoLock<thunk::PPB_FileIO_API> enter(file_io, true);
405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (enter.failed())
415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return PP_ERROR_BADARGUMENT;
425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  FileIOResource* file_io_resource =
435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      static_cast<FileIOResource*>(enter.object());
4446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  scoped_refptr<FileIOResource::FileHolder> file_holder =
4546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      file_io_resource->file_holder();
4646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  if (!FileIOResource::FileHolder::IsValid(file_holder))
475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return PP_ERROR_FAILED;
485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (length < 0 || offset < 0 ||
495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      !base::IsValueInRangeForNumericType<off_t>(offset)) {
505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return PP_ERROR_BADARGUMENT;
515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!base::IsValueInRangeForNumericType<size_t>(length)) {
535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return PP_ERROR_NOMEMORY;
545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Ensure any bits we don't recognize are zero.
575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (protection &
585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      ~(PP_FILEMAPPROTECTION_READ | PP_FILEMAPPROTECTION_WRITE)) {
595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return PP_ERROR_BADARGUMENT;
605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (flags &
625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      ~(PP_FILEMAPFLAG_SHARED | PP_FILEMAPFLAG_PRIVATE |
635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        PP_FILEMAPFLAG_FIXED)) {
645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return PP_ERROR_BADARGUMENT;
655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Ensure at least one of SHARED and PRIVATE is set.
675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!(flags & (PP_FILEMAPFLAG_SHARED | PP_FILEMAPFLAG_PRIVATE)))
685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return PP_ERROR_BADARGUMENT;
695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Ensure at most one of SHARED and PRIVATE is set.
705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if ((flags & PP_FILEMAPFLAG_SHARED) &&
715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      (flags & PP_FILEMAPFLAG_PRIVATE)) {
725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return PP_ERROR_BADARGUMENT;
735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!address)
755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return PP_ERROR_BADARGUMENT;
765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::Callback<MapResult()> map_cb(
7846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      base::Bind(&FileMappingResource::DoMapBlocking, file_holder, *address,
795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 length, protection, flags, offset));
805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (callback->is_blocking()) {
815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // The plugin could release its reference to this instance when we release
825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // the proxy lock below.
835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    scoped_refptr<FileMappingResource> protect(this);
845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    MapResult map_result;
855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    {
865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      // Release the proxy lock while making a potentially slow file call.
875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      ProxyAutoUnlock unlock;
885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      map_result = map_cb.Run();
895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    OnMapCompleted(address, length, callback, map_result);
915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return map_result.result;
925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  } else {
935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    base::PostTaskAndReplyWithResult(
945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      PpapiGlobals::Get()->GetFileTaskRunner(),
955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      FROM_HERE,
965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      map_cb,
975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      RunWhileLocked(Bind(&FileMappingResource::OnMapCompleted,
985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                          this,
995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                          base::Unretained(address),
1005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                          length,
1015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                          callback)));
1025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return PP_OK_COMPLETIONPENDING;
1035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)int32_t FileMappingResource::Unmap(PP_Instance /* instance */,
1075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                   const void* address,
1085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                   int64_t length,
1095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                   scoped_refptr<TrackedCallback> callback) {
1105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!address)
1115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return PP_ERROR_BADARGUMENT;
1125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!base::IsValueInRangeForNumericType<size_t>(length))
1135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return PP_ERROR_BADARGUMENT;
1145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::Callback<int32_t()> unmap_cb(
1165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      base::Bind(&FileMappingResource::DoUnmapBlocking, address, length));
1175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (callback->is_blocking()) {
1185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // Release the proxy lock while making a potentially slow file call.
1195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    ProxyAutoUnlock unlock;
1205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return unmap_cb.Run();
1215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  } else {
1225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    base::PostTaskAndReplyWithResult(
1235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      PpapiGlobals::Get()->GetFileTaskRunner(),
1245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      FROM_HERE,
1255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      unmap_cb,
1265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      RunWhileLocked(Bind(&TrackedCallback::Run, callback)));
1275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return PP_OK_COMPLETIONPENDING;
1285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)int64_t FileMappingResource::GetMapPageSize(PP_Instance /* instance */) {
1325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return DoGetMapPageSize();
1335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void FileMappingResource::OnMapCompleted(
1365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    void** mapped_address_out_param,
1375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    int64_t length,
1385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    scoped_refptr<TrackedCallback> callback,
1395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const MapResult& map_result) {
1405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (callback->aborted()) {
1415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (map_result.result == PP_OK) {
1425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      // If the Map operation was successful, we need to Unmap to avoid leaks.
1435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      // The plugin won't get the address, so doesn't have a chance to do the
1445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      // Unmap.
1455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      PpapiGlobals::Get()->GetFileTaskRunner()->PostTask(
1465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          FROM_HERE,
1475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          base::Bind(base::IgnoreResult(&FileMappingResource::DoUnmapBlocking),
1485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                     map_result.address,
1495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                     length));
1505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
1515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
1525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (map_result.result == PP_OK)
1545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    *mapped_address_out_param = map_result.address;
1555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!callback->is_blocking())
1565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    callback->Run(map_result.result);
1575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}  // namespace proxy
1605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}  // namespace ppapi
161