1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "ppapi/proxy/file_mapping_resource.h"
6
7 #include "base/bind.h"
8 #include "base/numerics/safe_conversions.h"
9 #include "base/task_runner_util.h"
10 #include "ppapi/c/pp_errors.h"
11 #include "ppapi/shared_impl/tracked_callback.h"
12 #include "ppapi/shared_impl/var.h"
13 #include "ppapi/thunk/enter.h"
14 #include "ppapi/thunk/ppb_file_io_api.h"
15
16 namespace ppapi {
17 namespace proxy {
18
FileMappingResource(Connection connection,PP_Instance instance)19 FileMappingResource::FileMappingResource(Connection connection,
20 PP_Instance instance)
21 : PluginResource(connection, instance) {
22 }
23
~FileMappingResource()24 FileMappingResource::~FileMappingResource() {
25 }
26
AsPPB_FileMapping_API()27 thunk::PPB_FileMapping_API* FileMappingResource::AsPPB_FileMapping_API() {
28 return this;
29 }
30
Map(PP_Instance,PP_Resource file_io,int64_t length,uint32_t protection,uint32_t flags,int64_t offset,void ** address,scoped_refptr<TrackedCallback> callback)31 int32_t FileMappingResource::Map(PP_Instance /* instance */,
32 PP_Resource file_io,
33 int64_t length,
34 uint32_t protection,
35 uint32_t flags,
36 int64_t offset,
37 void** address,
38 scoped_refptr<TrackedCallback> callback) {
39 thunk::EnterResourceNoLock<thunk::PPB_FileIO_API> enter(file_io, true);
40 if (enter.failed())
41 return PP_ERROR_BADARGUMENT;
42 FileIOResource* file_io_resource =
43 static_cast<FileIOResource*>(enter.object());
44 scoped_refptr<FileIOResource::FileHolder> file_holder =
45 file_io_resource->file_holder();
46 if (!FileIOResource::FileHolder::IsValid(file_holder))
47 return PP_ERROR_FAILED;
48 if (length < 0 || offset < 0 ||
49 !base::IsValueInRangeForNumericType<off_t>(offset)) {
50 return PP_ERROR_BADARGUMENT;
51 }
52 if (!base::IsValueInRangeForNumericType<size_t>(length)) {
53 return PP_ERROR_NOMEMORY;
54 }
55
56 // Ensure any bits we don't recognize are zero.
57 if (protection &
58 ~(PP_FILEMAPPROTECTION_READ | PP_FILEMAPPROTECTION_WRITE)) {
59 return PP_ERROR_BADARGUMENT;
60 }
61 if (flags &
62 ~(PP_FILEMAPFLAG_SHARED | PP_FILEMAPFLAG_PRIVATE |
63 PP_FILEMAPFLAG_FIXED)) {
64 return PP_ERROR_BADARGUMENT;
65 }
66 // Ensure at least one of SHARED and PRIVATE is set.
67 if (!(flags & (PP_FILEMAPFLAG_SHARED | PP_FILEMAPFLAG_PRIVATE)))
68 return PP_ERROR_BADARGUMENT;
69 // Ensure at most one of SHARED and PRIVATE is set.
70 if ((flags & PP_FILEMAPFLAG_SHARED) &&
71 (flags & PP_FILEMAPFLAG_PRIVATE)) {
72 return PP_ERROR_BADARGUMENT;
73 }
74 if (!address)
75 return PP_ERROR_BADARGUMENT;
76
77 base::Callback<MapResult()> map_cb(
78 base::Bind(&FileMappingResource::DoMapBlocking, file_holder, *address,
79 length, protection, flags, offset));
80 if (callback->is_blocking()) {
81 // The plugin could release its reference to this instance when we release
82 // the proxy lock below.
83 scoped_refptr<FileMappingResource> protect(this);
84 MapResult map_result;
85 {
86 // Release the proxy lock while making a potentially slow file call.
87 ProxyAutoUnlock unlock;
88 map_result = map_cb.Run();
89 }
90 OnMapCompleted(address, length, callback, map_result);
91 return map_result.result;
92 } else {
93 base::PostTaskAndReplyWithResult(
94 PpapiGlobals::Get()->GetFileTaskRunner(),
95 FROM_HERE,
96 map_cb,
97 RunWhileLocked(Bind(&FileMappingResource::OnMapCompleted,
98 this,
99 base::Unretained(address),
100 length,
101 callback)));
102 return PP_OK_COMPLETIONPENDING;
103 }
104 }
105
Unmap(PP_Instance,const void * address,int64_t length,scoped_refptr<TrackedCallback> callback)106 int32_t FileMappingResource::Unmap(PP_Instance /* instance */,
107 const void* address,
108 int64_t length,
109 scoped_refptr<TrackedCallback> callback) {
110 if (!address)
111 return PP_ERROR_BADARGUMENT;
112 if (!base::IsValueInRangeForNumericType<size_t>(length))
113 return PP_ERROR_BADARGUMENT;
114
115 base::Callback<int32_t()> unmap_cb(
116 base::Bind(&FileMappingResource::DoUnmapBlocking, address, length));
117 if (callback->is_blocking()) {
118 // Release the proxy lock while making a potentially slow file call.
119 ProxyAutoUnlock unlock;
120 return unmap_cb.Run();
121 } else {
122 base::PostTaskAndReplyWithResult(
123 PpapiGlobals::Get()->GetFileTaskRunner(),
124 FROM_HERE,
125 unmap_cb,
126 RunWhileLocked(Bind(&TrackedCallback::Run, callback)));
127 return PP_OK_COMPLETIONPENDING;
128 }
129 }
130
GetMapPageSize(PP_Instance)131 int64_t FileMappingResource::GetMapPageSize(PP_Instance /* instance */) {
132 return DoGetMapPageSize();
133 }
134
OnMapCompleted(void ** mapped_address_out_param,int64_t length,scoped_refptr<TrackedCallback> callback,const MapResult & map_result)135 void FileMappingResource::OnMapCompleted(
136 void** mapped_address_out_param,
137 int64_t length,
138 scoped_refptr<TrackedCallback> callback,
139 const MapResult& map_result) {
140 if (callback->aborted()) {
141 if (map_result.result == PP_OK) {
142 // If the Map operation was successful, we need to Unmap to avoid leaks.
143 // The plugin won't get the address, so doesn't have a chance to do the
144 // Unmap.
145 PpapiGlobals::Get()->GetFileTaskRunner()->PostTask(
146 FROM_HERE,
147 base::Bind(base::IgnoreResult(&FileMappingResource::DoUnmapBlocking),
148 map_result.address,
149 length));
150 }
151 return;
152 }
153 if (map_result.result == PP_OK)
154 *mapped_address_out_param = map_result.address;
155 if (!callback->is_blocking())
156 callback->Run(map_result.result);
157 }
158
159 } // namespace proxy
160 } // namespace ppapi
161