Do PPB_FileIO Query and Read in the plugin process.
[chromium-blink-merge.git] / ppapi / proxy / file_io_resource.cc
blob0f6ad00c6ed28363fcc44095ba42bdca8fdcd23b
1 // Copyright (c) 2012 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.
5 #include "ppapi/proxy/file_io_resource.h"
7 #include "base/bind.h"
8 #include "base/files/file_util_proxy.h"
9 #include "ipc/ipc_message.h"
10 #include "ppapi/c/pp_errors.h"
11 #include "ppapi/proxy/plugin_globals.h"
12 #include "ppapi/proxy/ppapi_messages.h"
13 #include "ppapi/shared_impl/array_writer.h"
14 #include "ppapi/shared_impl/file_type_conversion.h"
15 #include "ppapi/shared_impl/ppapi_globals.h"
16 #include "ppapi/shared_impl/proxy_lock.h"
17 #include "ppapi/shared_impl/resource_tracker.h"
18 #include "ppapi/thunk/enter.h"
19 #include "ppapi/thunk/ppb_file_ref_api.h"
21 using ppapi::thunk::EnterResourceNoLock;
22 using ppapi::thunk::PPB_FileIO_API;
23 using ppapi::thunk::PPB_FileRef_API;
25 namespace {
27 // An adapter to let Read() share the same implementation with ReadToArray().
28 void* DummyGetDataBuffer(void* user_data, uint32_t count, uint32_t size) {
29 return user_data;
32 // Dummy close callback allows us to call CloseFileHandle in the destructor.
33 void DummyCloseCallback(base::PlatformFileError error_code) {
36 } // namespace
38 namespace ppapi {
39 namespace proxy {
41 FileIOResource::FileIOResource(Connection connection, PP_Instance instance)
42 : PluginResource(connection, instance),
43 file_handle_(PP_kInvalidFileHandle),
44 file_system_type_(PP_FILESYSTEMTYPE_INVALID) {
45 SendCreate(RENDERER, PpapiHostMsg_FileIO_Create());
48 FileIOResource::~FileIOResource() {
49 CloseFileHandle();
52 PPB_FileIO_API* FileIOResource::AsPPB_FileIO_API() {
53 return this;
56 int32_t FileIOResource::Open(PP_Resource file_ref,
57 int32_t open_flags,
58 scoped_refptr<TrackedCallback> callback) {
59 EnterResourceNoLock<PPB_FileRef_API> enter(file_ref, true);
60 if (enter.failed())
61 return PP_ERROR_BADRESOURCE;
63 PPB_FileRef_API* file_ref_api = enter.object();
64 PP_FileSystemType type = file_ref_api->GetFileSystemType();
65 if (type != PP_FILESYSTEMTYPE_LOCALPERSISTENT &&
66 type != PP_FILESYSTEMTYPE_LOCALTEMPORARY &&
67 type != PP_FILESYSTEMTYPE_EXTERNAL &&
68 type != PP_FILESYSTEMTYPE_ISOLATED) {
69 NOTREACHED();
70 return PP_ERROR_FAILED;
72 file_system_type_ = type;
74 int32_t rv = state_manager_.CheckOperationState(
75 FileIOStateManager::OPERATION_EXCLUSIVE, false);
76 if (rv != PP_OK)
77 return rv;
79 Call<PpapiPluginMsg_FileIO_OpenReply>(RENDERER,
80 PpapiHostMsg_FileIO_Open(
81 enter.resource()->host_resource().host_resource(),
82 open_flags),
83 base::Bind(&FileIOResource::OnPluginMsgOpenFileComplete, this,
84 callback));
86 state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_EXCLUSIVE);
87 return PP_OK_COMPLETIONPENDING;
90 int32_t FileIOResource::Query(PP_FileInfo* info,
91 scoped_refptr<TrackedCallback> callback) {
92 int32_t rv = state_manager_.CheckOperationState(
93 FileIOStateManager::OPERATION_EXCLUSIVE, true);
94 if (rv != PP_OK)
95 return rv;
97 if (file_handle_ == base::kInvalidPlatformFileValue)
98 return PP_ERROR_FAILED;
100 if (!base::FileUtilProxy::GetFileInfoFromPlatformFile(
101 PpapiGlobals::Get()->GetFileTaskRunner(pp_instance()),
102 file_handle_,
103 RunWhileLocked(base::Bind(&FileIOResource::OnQueryComplete, this,
104 callback, info)))) {
105 return PP_ERROR_FAILED;
108 state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_EXCLUSIVE);
109 return PP_OK_COMPLETIONPENDING;
112 int32_t FileIOResource::Touch(PP_Time last_access_time,
113 PP_Time last_modified_time,
114 scoped_refptr<TrackedCallback> callback) {
115 int32_t rv = state_manager_.CheckOperationState(
116 FileIOStateManager::OPERATION_EXCLUSIVE, true);
117 if (rv != PP_OK)
118 return rv;
120 Call<PpapiPluginMsg_FileIO_GeneralReply>(RENDERER,
121 PpapiHostMsg_FileIO_Touch(last_access_time, last_modified_time),
122 base::Bind(&FileIOResource::OnPluginMsgGeneralComplete, this,
123 callback));
125 state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_EXCLUSIVE);
126 return PP_OK_COMPLETIONPENDING;
129 int32_t FileIOResource::Read(int64_t offset,
130 char* buffer,
131 int32_t bytes_to_read,
132 scoped_refptr<TrackedCallback> callback) {
133 int32_t rv = state_manager_.CheckOperationState(
134 FileIOStateManager::OPERATION_READ, true);
135 if (rv != PP_OK)
136 return rv;
138 PP_ArrayOutput output_adapter;
139 output_adapter.GetDataBuffer = &DummyGetDataBuffer;
140 output_adapter.user_data = buffer;
141 return ReadValidated(offset, bytes_to_read, output_adapter, callback);
144 int32_t FileIOResource::ReadToArray(int64_t offset,
145 int32_t max_read_length,
146 PP_ArrayOutput* array_output,
147 scoped_refptr<TrackedCallback> callback) {
148 DCHECK(array_output);
149 int32_t rv = state_manager_.CheckOperationState(
150 FileIOStateManager::OPERATION_READ, true);
151 if (rv != PP_OK)
152 return rv;
154 return ReadValidated(offset, max_read_length, *array_output, callback);
157 int32_t FileIOResource::Write(int64_t offset,
158 const char* buffer,
159 int32_t bytes_to_write,
160 scoped_refptr<TrackedCallback> callback) {
161 int32_t rv = state_manager_.CheckOperationState(
162 FileIOStateManager::OPERATION_WRITE, true);
163 if (rv != PP_OK)
164 return rv;
166 // TODO(brettw) it would be nice to use a shared memory buffer for large
167 // writes rather than having to copy to a string (which will involve a number
168 // of extra copies to serialize over IPC).
169 Call<PpapiPluginMsg_FileIO_GeneralReply>(RENDERER,
170 PpapiHostMsg_FileIO_Write(offset, std::string(buffer, bytes_to_write)),
171 base::Bind(&FileIOResource::OnPluginMsgGeneralComplete, this,
172 callback));
174 state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_WRITE);
175 return PP_OK_COMPLETIONPENDING;
178 int32_t FileIOResource::SetLength(int64_t length,
179 scoped_refptr<TrackedCallback> callback) {
180 int32_t rv = state_manager_.CheckOperationState(
181 FileIOStateManager::OPERATION_EXCLUSIVE, true);
182 if (rv != PP_OK)
183 return rv;
185 Call<PpapiPluginMsg_FileIO_GeneralReply>(RENDERER,
186 PpapiHostMsg_FileIO_SetLength(length),
187 base::Bind(&FileIOResource::OnPluginMsgGeneralComplete, this,
188 callback));
190 state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_EXCLUSIVE);
191 return PP_OK_COMPLETIONPENDING;
194 int32_t FileIOResource::Flush(scoped_refptr<TrackedCallback> callback) {
195 int32_t rv = state_manager_.CheckOperationState(
196 FileIOStateManager::OPERATION_EXCLUSIVE, true);
197 if (rv != PP_OK)
198 return rv;
200 Call<PpapiPluginMsg_FileIO_GeneralReply>(RENDERER,
201 PpapiHostMsg_FileIO_Flush(),
202 base::Bind(&FileIOResource::OnPluginMsgGeneralComplete, this,
203 callback));
205 state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_EXCLUSIVE);
206 return PP_OK_COMPLETIONPENDING;
209 void FileIOResource::Close() {
210 CloseFileHandle();
211 Post(RENDERER, PpapiHostMsg_FileIO_Close());
214 int32_t FileIOResource::GetOSFileDescriptor() {
215 int32_t file_descriptor;
216 // Only available when running in process.
217 SyncCall<PpapiPluginMsg_FileIO_GetOSFileDescriptorReply>(
218 RENDERER, PpapiHostMsg_FileIO_GetOSFileDescriptor(), &file_descriptor);
219 return file_descriptor;
222 int32_t FileIOResource::RequestOSFileHandle(
223 PP_FileHandle* handle,
224 scoped_refptr<TrackedCallback> callback) {
225 int32_t rv = state_manager_.CheckOperationState(
226 FileIOStateManager::OPERATION_EXCLUSIVE, true);
227 if (rv != PP_OK)
228 return rv;
230 Call<PpapiPluginMsg_FileIO_RequestOSFileHandleReply>(RENDERER,
231 PpapiHostMsg_FileIO_RequestOSFileHandle(),
232 base::Bind(&FileIOResource::OnPluginMsgRequestOSFileHandleComplete, this,
233 callback, handle));
235 state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_EXCLUSIVE);
236 return PP_OK_COMPLETIONPENDING;
239 int32_t FileIOResource::WillWrite(int64_t offset,
240 int32_t bytes_to_write,
241 scoped_refptr<TrackedCallback> callback) {
242 Call<PpapiPluginMsg_FileIO_GeneralReply>(RENDERER,
243 PpapiHostMsg_FileIO_WillWrite(offset, bytes_to_write),
244 base::Bind(&FileIOResource::OnPluginMsgGeneralComplete, this,
245 callback));
247 state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_EXCLUSIVE);
248 return PP_OK_COMPLETIONPENDING;
251 int32_t FileIOResource::WillSetLength(int64_t length,
252 scoped_refptr<TrackedCallback> callback) {
253 Call<PpapiPluginMsg_FileIO_GeneralReply>(RENDERER,
254 PpapiHostMsg_FileIO_WillSetLength(length),
255 base::Bind(&FileIOResource::OnPluginMsgGeneralComplete, this,
256 callback));
258 state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_EXCLUSIVE);
259 return PP_OK_COMPLETIONPENDING;
262 int32_t FileIOResource::ReadValidated(int64_t offset,
263 int32_t bytes_to_read,
264 const PP_ArrayOutput& array_output,
265 scoped_refptr<TrackedCallback> callback) {
266 if (file_handle_ == base::kInvalidPlatformFileValue)
267 return PP_ERROR_FAILED;
269 if (!base::FileUtilProxy::Read(
270 PpapiGlobals::Get()->GetFileTaskRunner(pp_instance()),
271 file_handle_,
272 offset,
273 bytes_to_read,
274 RunWhileLocked(base::Bind(&FileIOResource::OnReadComplete, this,
275 callback, array_output)))) {
276 return PP_ERROR_FAILED;
279 state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_READ);
280 return PP_OK_COMPLETIONPENDING;
283 void FileIOResource::CloseFileHandle() {
284 if (file_handle_ != base::kInvalidPlatformFileValue) {
285 base::FileUtilProxy::Close(
286 PpapiGlobals::Get()->GetFileTaskRunner(pp_instance()),
287 file_handle_,
288 base::Bind(&DummyCloseCallback));
289 file_handle_ = base::kInvalidPlatformFileValue;
293 void FileIOResource::OnQueryComplete(
294 scoped_refptr<TrackedCallback> callback,
295 PP_FileInfo* output_info,
296 base::PlatformFileError error_code,
297 const base::PlatformFileInfo& file_info) {
298 DCHECK(state_manager_.get_pending_operation() ==
299 FileIOStateManager::OPERATION_EXCLUSIVE);
301 if (!TrackedCallback::IsPending(callback)) {
302 state_manager_.SetOperationFinished();
303 return;
306 int32_t result = ::ppapi::PlatformFileErrorToPepperError(error_code);
307 if (result == PP_OK) {
308 ppapi::PlatformFileInfoToPepperFileInfo(file_info, file_system_type_,
309 output_info);
312 // End this operation now, so the user's callback can execute another FileIO
313 // operation, assuming there are no other pending operations.
314 state_manager_.SetOperationFinished();
315 callback->Run(result);
318 void FileIOResource::OnReadComplete(
319 scoped_refptr<TrackedCallback> callback,
320 PP_ArrayOutput array_output,
321 base::PlatformFileError error_code,
322 const char* data, int bytes_read) {
323 DCHECK(state_manager_.get_pending_operation() ==
324 FileIOStateManager::OPERATION_READ);
326 if (!TrackedCallback::IsPending(callback)) {
327 state_manager_.SetOperationFinished();
328 return;
331 int32_t result = ::ppapi::PlatformFileErrorToPepperError(error_code);
332 if (result == PP_OK) {
333 result = std::max(0, bytes_read);
334 ArrayWriter output;
335 output.set_pp_array_output(array_output);
336 if (output.is_valid())
337 output.StoreArray(data, result);
338 else
339 result = PP_ERROR_FAILED;
342 // End this operation now, so the user's callback can execute another FileIO
343 // operation, assuming there are no other pending operations.
344 state_manager_.SetOperationFinished();
345 callback->Run(result);
348 void FileIOResource::OnPluginMsgGeneralComplete(
349 scoped_refptr<TrackedCallback> callback,
350 const ResourceMessageReplyParams& params) {
351 DCHECK(state_manager_.get_pending_operation() ==
352 FileIOStateManager::OPERATION_EXCLUSIVE ||
353 state_manager_.get_pending_operation() ==
354 FileIOStateManager::OPERATION_WRITE);
355 // End this operation now, so the user's callback can execute another FileIO
356 // operation, assuming there are no other pending operations.
357 state_manager_.SetOperationFinished();
358 callback->Run(params.result());
361 void FileIOResource::OnPluginMsgOpenFileComplete(
362 scoped_refptr<TrackedCallback> callback,
363 const ResourceMessageReplyParams& params) {
364 DCHECK(state_manager_.get_pending_operation() ==
365 FileIOStateManager::OPERATION_EXCLUSIVE);
366 if (params.result() == PP_OK)
367 state_manager_.SetOpenSucceed();
369 int32_t result = params.result();
370 IPC::PlatformFileForTransit transit_file;
371 if (result == PP_OK && !params.TakeFileHandleAtIndex(0, &transit_file))
372 result = PP_ERROR_FAILED;
373 file_handle_ = IPC::PlatformFileForTransitToPlatformFile(transit_file);
375 // End this operation now, so the user's callback can execute another FileIO
376 // operation, assuming there are no other pending operations.
377 state_manager_.SetOperationFinished();
378 callback->Run(params.result());
381 void FileIOResource::OnPluginMsgRequestOSFileHandleComplete(
382 scoped_refptr<TrackedCallback> callback,
383 PP_FileHandle* output_handle,
384 const ResourceMessageReplyParams& params) {
385 DCHECK(state_manager_.get_pending_operation() ==
386 FileIOStateManager::OPERATION_EXCLUSIVE);
388 if (!TrackedCallback::IsPending(callback)) {
389 state_manager_.SetOperationFinished();
390 return;
393 int32_t result = params.result();
394 IPC::PlatformFileForTransit transit_file;
395 if (!params.TakeFileHandleAtIndex(0, &transit_file))
396 result = PP_ERROR_FAILED;
397 *output_handle = IPC::PlatformFileForTransitToPlatformFile(transit_file);
399 // End this operation now, so the user's callback can execute another FileIO
400 // operation, assuming there are no other pending operations.
401 state_manager_.SetOperationFinished();
402 callback->Run(result);
405 } // namespace proxy
406 } // namespace ppapi