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"
8 #include "base/task_runner_util.h"
9 #include "ipc/ipc_message.h"
10 #include "ppapi/c/pp_errors.h"
11 #include "ppapi/proxy/ppapi_messages.h"
12 #include "ppapi/shared_impl/array_writer.h"
13 #include "ppapi/shared_impl/file_ref_create_info.h"
14 #include "ppapi/shared_impl/file_system_util.h"
15 #include "ppapi/shared_impl/file_type_conversion.h"
16 #include "ppapi/shared_impl/ppapi_globals.h"
17 #include "ppapi/shared_impl/proxy_lock.h"
18 #include "ppapi/shared_impl/resource_tracker.h"
19 #include "ppapi/thunk/enter.h"
20 #include "ppapi/thunk/ppb_file_ref_api.h"
21 #include "ppapi/thunk/ppb_file_system_api.h"
23 using ppapi::thunk::EnterResourceNoLock
;
24 using ppapi::thunk::PPB_FileIO_API
;
25 using ppapi::thunk::PPB_FileRef_API
;
26 using ppapi::thunk::PPB_FileSystem_API
;
30 // We must allocate a buffer sized according to the request of the plugin. To
31 // reduce the chance of out-of-memory errors, we cap the read and write size to
32 // 32MB. This is OK since the API specifies that it may perform a partial read
34 static const int32_t kMaxReadWriteSize
= 32 * 1024 * 1024; // 32MB
36 // An adapter to let Read() share the same implementation with ReadToArray().
37 void* DummyGetDataBuffer(void* user_data
, uint32_t count
, uint32_t size
) {
41 // File thread task to close the file handle.
42 void DoClose(base::File auto_close_file
) {
50 FileIOResource::QueryOp::QueryOp(scoped_refptr
<FileHolder
> file_holder
)
51 : file_holder_(file_holder
) {
52 DCHECK(file_holder_
.get());
55 FileIOResource::QueryOp::~QueryOp() {
58 int32_t FileIOResource::QueryOp::DoWork() {
59 return file_holder_
->file()->GetInfo(&file_info_
) ? PP_OK
: PP_ERROR_FAILED
;
62 FileIOResource::ReadOp::ReadOp(scoped_refptr
<FileHolder
> file_holder
,
64 int32_t bytes_to_read
)
65 : file_holder_(file_holder
),
67 bytes_to_read_(bytes_to_read
) {
68 DCHECK(file_holder_
.get());
71 FileIOResource::ReadOp::~ReadOp() {
74 int32_t FileIOResource::ReadOp::DoWork() {
75 DCHECK(!buffer_
.get());
76 buffer_
.reset(new char[bytes_to_read_
]);
77 return file_holder_
->file()->Read(offset_
, buffer_
.get(), bytes_to_read_
);
80 FileIOResource::WriteOp::WriteOp(scoped_refptr
<FileHolder
> file_holder
,
82 scoped_ptr
<char[]> buffer
,
83 int32_t bytes_to_write
,
85 : file_holder_(file_holder
),
87 buffer_(buffer
.Pass()),
88 bytes_to_write_(bytes_to_write
),
92 FileIOResource::WriteOp::~WriteOp() {
95 int32_t FileIOResource::WriteOp::DoWork() {
96 // In append mode, we can't call Write, since NaCl doesn't implement fcntl,
97 // causing the function to call pwrite, which is incorrect.
99 return file_holder_
->file()->WriteAtCurrentPos(buffer_
.get(),
102 return file_holder_
->file()->Write(offset_
, buffer_
.get(), bytes_to_write_
);
106 FileIOResource::FileIOResource(Connection connection
, PP_Instance instance
)
107 : PluginResource(connection
, instance
),
108 file_system_type_(PP_FILESYSTEMTYPE_INVALID
),
110 max_written_offset_(0),
111 append_mode_write_amount_(0),
113 called_close_(false) {
114 SendCreate(BROWSER
, PpapiHostMsg_FileIO_Create());
117 FileIOResource::~FileIOResource() {
121 PPB_FileIO_API
* FileIOResource::AsPPB_FileIO_API() {
125 int32_t FileIOResource::Open(PP_Resource file_ref
,
127 scoped_refptr
<TrackedCallback
> callback
) {
128 EnterResourceNoLock
<PPB_FileRef_API
> enter_file_ref(file_ref
, true);
129 if (enter_file_ref
.failed())
130 return PP_ERROR_BADRESOURCE
;
132 PPB_FileRef_API
* file_ref_api
= enter_file_ref
.object();
133 const FileRefCreateInfo
& create_info
= file_ref_api
->GetCreateInfo();
134 if (!FileSystemTypeIsValid(create_info
.file_system_type
)) {
136 return PP_ERROR_FAILED
;
138 int32_t rv
= state_manager_
.CheckOperationState(
139 FileIOStateManager::OPERATION_EXCLUSIVE
, false);
143 open_flags_
= open_flags
;
144 file_system_type_
= create_info
.file_system_type
;
146 if (create_info
.file_system_plugin_resource
) {
147 EnterResourceNoLock
<PPB_FileSystem_API
> enter_file_system(
148 create_info
.file_system_plugin_resource
, true);
149 if (enter_file_system
.failed())
150 return PP_ERROR_FAILED
;
151 // Take a reference on the FileSystem resource. The FileIO host uses the
152 // FileSystem host for running tasks and checking quota.
153 file_system_resource_
= enter_file_system
.resource();
156 // Take a reference on the FileRef resource while we're opening the file; we
157 // don't want the plugin destroying it during the Open operation.
158 file_ref_
= enter_file_ref
.resource();
160 Call
<PpapiPluginMsg_FileIO_OpenReply
>(BROWSER
,
161 PpapiHostMsg_FileIO_Open(
164 base::Bind(&FileIOResource::OnPluginMsgOpenFileComplete
, this,
167 state_manager_
.SetPendingOperation(FileIOStateManager::OPERATION_EXCLUSIVE
);
168 return PP_OK_COMPLETIONPENDING
;
171 int32_t FileIOResource::Query(PP_FileInfo
* info
,
172 scoped_refptr
<TrackedCallback
> callback
) {
173 int32_t rv
= state_manager_
.CheckOperationState(
174 FileIOStateManager::OPERATION_EXCLUSIVE
, true);
178 return PP_ERROR_BADARGUMENT
;
179 if (!FileHolder::IsValid(file_holder_
))
180 return PP_ERROR_FAILED
;
182 state_manager_
.SetPendingOperation(FileIOStateManager::OPERATION_EXCLUSIVE
);
184 // If the callback is blocking, perform the task on the calling thread.
185 if (callback
->is_blocking()) {
186 int32_t result
= PP_ERROR_FAILED
;
187 base::File::Info file_info
;
188 // The plugin could release its reference to this instance when we release
189 // the proxy lock below.
190 scoped_refptr
<FileIOResource
> protect(this);
192 // Release the proxy lock while making a potentially slow file call.
193 ProxyAutoUnlock unlock
;
194 if (file_holder_
->file()->GetInfo(&file_info
))
197 if (result
== PP_OK
) {
198 // This writes the file info into the plugin's PP_FileInfo struct.
199 ppapi::FileInfoToPepperFileInfo(file_info
,
203 state_manager_
.SetOperationFinished();
207 // For the non-blocking case, post a task to the file thread and add a
208 // completion task to write the result.
209 scoped_refptr
<QueryOp
> query_op(new QueryOp(file_holder_
));
210 base::PostTaskAndReplyWithResult(
211 PpapiGlobals::Get()->GetFileTaskRunner(),
213 Bind(&FileIOResource::QueryOp::DoWork
, query_op
),
214 RunWhileLocked(Bind(&TrackedCallback::Run
, callback
)));
215 callback
->set_completion_task(
216 Bind(&FileIOResource::OnQueryComplete
, this, query_op
, info
));
218 return PP_OK_COMPLETIONPENDING
;
221 int32_t FileIOResource::Touch(PP_Time last_access_time
,
222 PP_Time last_modified_time
,
223 scoped_refptr
<TrackedCallback
> callback
) {
224 int32_t rv
= state_manager_
.CheckOperationState(
225 FileIOStateManager::OPERATION_EXCLUSIVE
, true);
229 Call
<PpapiPluginMsg_FileIO_GeneralReply
>(BROWSER
,
230 PpapiHostMsg_FileIO_Touch(last_access_time
, last_modified_time
),
231 base::Bind(&FileIOResource::OnPluginMsgGeneralComplete
, this,
234 state_manager_
.SetPendingOperation(FileIOStateManager::OPERATION_EXCLUSIVE
);
235 return PP_OK_COMPLETIONPENDING
;
238 int32_t FileIOResource::Read(int64_t offset
,
240 int32_t bytes_to_read
,
241 scoped_refptr
<TrackedCallback
> callback
) {
242 int32_t rv
= state_manager_
.CheckOperationState(
243 FileIOStateManager::OPERATION_READ
, true);
247 PP_ArrayOutput output_adapter
;
248 output_adapter
.GetDataBuffer
= &DummyGetDataBuffer
;
249 output_adapter
.user_data
= buffer
;
250 return ReadValidated(offset
, bytes_to_read
, output_adapter
, callback
);
253 int32_t FileIOResource::ReadToArray(int64_t offset
,
254 int32_t max_read_length
,
255 PP_ArrayOutput
* array_output
,
256 scoped_refptr
<TrackedCallback
> callback
) {
257 DCHECK(array_output
);
258 int32_t rv
= state_manager_
.CheckOperationState(
259 FileIOStateManager::OPERATION_READ
, true);
263 return ReadValidated(offset
, max_read_length
, *array_output
, callback
);
266 int32_t FileIOResource::Write(int64_t offset
,
268 int32_t bytes_to_write
,
269 scoped_refptr
<TrackedCallback
> callback
) {
271 return PP_ERROR_FAILED
;
272 if (offset
< 0 || bytes_to_write
< 0)
273 return PP_ERROR_FAILED
;
274 if (!FileHolder::IsValid(file_holder_
))
275 return PP_ERROR_FAILED
;
277 int32_t rv
= state_manager_
.CheckOperationState(
278 FileIOStateManager::OPERATION_WRITE
, true);
282 state_manager_
.SetPendingOperation(FileIOStateManager::OPERATION_WRITE
);
285 int64_t increase
= 0;
286 uint64_t max_offset
= 0;
287 bool append
= (open_flags_
& PP_FILEOPENFLAG_APPEND
) != 0;
289 increase
= bytes_to_write
;
291 uint64_t max_offset
= offset
+ bytes_to_write
;
292 if (max_offset
> static_cast<uint64_t>(kint64max
))
293 return PP_ERROR_FAILED
; // amount calculation would overflow.
294 increase
= static_cast<int64_t>(max_offset
) - max_written_offset_
;
298 // Request a quota reservation. This makes the Write asynchronous, so we
299 // must copy the plugin's buffer.
300 scoped_ptr
<char[]> copy(new char[bytes_to_write
]);
301 memcpy(copy
.get(), buffer
, bytes_to_write
);
303 file_system_resource_
->AsPPB_FileSystem_API()->RequestQuota(
305 base::Bind(&FileIOResource::OnRequestWriteQuotaComplete
,
311 if (result
== PP_OK_COMPLETIONPENDING
)
312 return PP_OK_COMPLETIONPENDING
;
313 DCHECK(result
== increase
);
316 append_mode_write_amount_
+= bytes_to_write
;
318 max_written_offset_
= max_offset
;
321 return WriteValidated(offset
, buffer
, bytes_to_write
, callback
);
324 int32_t FileIOResource::SetLength(int64_t length
,
325 scoped_refptr
<TrackedCallback
> callback
) {
326 int32_t rv
= state_manager_
.CheckOperationState(
327 FileIOStateManager::OPERATION_EXCLUSIVE
, true);
331 return PP_ERROR_FAILED
;
334 int64_t increase
= length
- max_written_offset_
;
337 file_system_resource_
->AsPPB_FileSystem_API()->RequestQuota(
339 base::Bind(&FileIOResource::OnRequestSetLengthQuotaComplete
,
342 if (result
== PP_OK_COMPLETIONPENDING
) {
343 state_manager_
.SetPendingOperation(
344 FileIOStateManager::OPERATION_EXCLUSIVE
);
345 return PP_OK_COMPLETIONPENDING
;
347 DCHECK(result
== increase
);
348 max_written_offset_
= length
;
352 state_manager_
.SetPendingOperation(FileIOStateManager::OPERATION_EXCLUSIVE
);
353 SetLengthValidated(length
, callback
);
354 return PP_OK_COMPLETIONPENDING
;
357 int32_t FileIOResource::Flush(scoped_refptr
<TrackedCallback
> callback
) {
358 int32_t rv
= state_manager_
.CheckOperationState(
359 FileIOStateManager::OPERATION_EXCLUSIVE
, true);
363 Call
<PpapiPluginMsg_FileIO_GeneralReply
>(BROWSER
,
364 PpapiHostMsg_FileIO_Flush(),
365 base::Bind(&FileIOResource::OnPluginMsgGeneralComplete
, this,
368 state_manager_
.SetPendingOperation(FileIOStateManager::OPERATION_EXCLUSIVE
);
369 return PP_OK_COMPLETIONPENDING
;
372 int64_t FileIOResource::GetMaxWrittenOffset() const {
373 return max_written_offset_
;
376 int64_t FileIOResource::GetAppendModeWriteAmount() const {
377 return append_mode_write_amount_
;
380 void FileIOResource::SetMaxWrittenOffset(int64_t max_written_offset
) {
381 max_written_offset_
= max_written_offset
;
384 void FileIOResource::SetAppendModeWriteAmount(
385 int64_t append_mode_write_amount
) {
386 append_mode_write_amount_
= append_mode_write_amount
;
389 void FileIOResource::Close() {
393 called_close_
= true;
395 check_quota_
= false;
396 file_system_resource_
->AsPPB_FileSystem_API()->CloseQuotaFile(
400 if (file_holder_
.get())
403 Post(BROWSER
, PpapiHostMsg_FileIO_Close(
404 FileGrowth(max_written_offset_
, append_mode_write_amount_
)));
407 int32_t FileIOResource::RequestOSFileHandle(
408 PP_FileHandle
* handle
,
409 scoped_refptr
<TrackedCallback
> callback
) {
410 int32_t rv
= state_manager_
.CheckOperationState(
411 FileIOStateManager::OPERATION_EXCLUSIVE
, true);
415 Call
<PpapiPluginMsg_FileIO_RequestOSFileHandleReply
>(BROWSER
,
416 PpapiHostMsg_FileIO_RequestOSFileHandle(),
417 base::Bind(&FileIOResource::OnPluginMsgRequestOSFileHandleComplete
, this,
420 state_manager_
.SetPendingOperation(FileIOStateManager::OPERATION_EXCLUSIVE
);
421 return PP_OK_COMPLETIONPENDING
;
424 FileIOResource::FileHolder::FileHolder(PP_FileHandle file_handle
)
425 : file_(file_handle
) {
429 bool FileIOResource::FileHolder::IsValid(
430 const scoped_refptr
<FileIOResource::FileHolder
>& handle
) {
431 return handle
.get() && handle
->file_
.IsValid();
434 FileIOResource::FileHolder::~FileHolder() {
435 if (file_
.IsValid()) {
436 base::TaskRunner
* file_task_runner
=
437 PpapiGlobals::Get()->GetFileTaskRunner();
438 file_task_runner
->PostTask(FROM_HERE
,
439 base::Bind(&DoClose
, Passed(&file_
)));
443 int32_t FileIOResource::ReadValidated(int64_t offset
,
444 int32_t bytes_to_read
,
445 const PP_ArrayOutput
& array_output
,
446 scoped_refptr
<TrackedCallback
> callback
) {
447 if (bytes_to_read
< 0)
448 return PP_ERROR_FAILED
;
449 if (!FileHolder::IsValid(file_holder_
))
450 return PP_ERROR_FAILED
;
452 state_manager_
.SetPendingOperation(FileIOStateManager::OPERATION_READ
);
454 bytes_to_read
= std::min(bytes_to_read
, kMaxReadWriteSize
);
455 if (callback
->is_blocking()) {
456 char* buffer
= static_cast<char*>(
457 array_output
.GetDataBuffer(array_output
.user_data
, bytes_to_read
, 1));
458 int32_t result
= PP_ERROR_FAILED
;
459 // The plugin could release its reference to this instance when we release
460 // the proxy lock below.
461 scoped_refptr
<FileIOResource
> protect(this);
463 // Release the proxy lock while making a potentially slow file call.
464 ProxyAutoUnlock unlock
;
465 result
= file_holder_
->file()->Read(offset
, buffer
, bytes_to_read
);
467 result
= PP_ERROR_FAILED
;
469 state_manager_
.SetOperationFinished();
473 // For the non-blocking case, post a task to the file thread.
474 scoped_refptr
<ReadOp
> read_op(
475 new ReadOp(file_holder_
, offset
, bytes_to_read
));
476 base::PostTaskAndReplyWithResult(
477 PpapiGlobals::Get()->GetFileTaskRunner(),
479 Bind(&FileIOResource::ReadOp::DoWork
, read_op
),
480 RunWhileLocked(Bind(&TrackedCallback::Run
, callback
)));
481 callback
->set_completion_task(
482 Bind(&FileIOResource::OnReadComplete
, this, read_op
, array_output
));
484 return PP_OK_COMPLETIONPENDING
;
487 int32_t FileIOResource::WriteValidated(
490 int32_t bytes_to_write
,
491 scoped_refptr
<TrackedCallback
> callback
) {
492 bool append
= (open_flags_
& PP_FILEOPENFLAG_APPEND
) != 0;
493 if (callback
->is_blocking()) {
496 // Release the proxy lock while making a potentially slow file call.
497 ProxyAutoUnlock unlock
;
499 result
= file_holder_
->file()->WriteAtCurrentPos(buffer
,
502 result
= file_holder_
->file()->Write(offset
, buffer
, bytes_to_write
);
506 result
= PP_ERROR_FAILED
;
508 state_manager_
.SetOperationFinished();
512 // For the non-blocking case, post a task to the file thread. We must copy the
513 // plugin's buffer at this point.
514 scoped_ptr
<char[]> copy(new char[bytes_to_write
]);
515 memcpy(copy
.get(), buffer
, bytes_to_write
);
516 scoped_refptr
<WriteOp
> write_op(
517 new WriteOp(file_holder_
, offset
, copy
.Pass(), bytes_to_write
, append
));
518 base::PostTaskAndReplyWithResult(
519 PpapiGlobals::Get()->GetFileTaskRunner(),
521 Bind(&FileIOResource::WriteOp::DoWork
, write_op
),
522 RunWhileLocked(Bind(&TrackedCallback::Run
, callback
)));
523 callback
->set_completion_task(Bind(&FileIOResource::OnWriteComplete
, this));
525 return PP_OK_COMPLETIONPENDING
;
528 void FileIOResource::SetLengthValidated(
530 scoped_refptr
<TrackedCallback
> callback
) {
531 Call
<PpapiPluginMsg_FileIO_GeneralReply
>(BROWSER
,
532 PpapiHostMsg_FileIO_SetLength(length
),
533 base::Bind(&FileIOResource::OnPluginMsgGeneralComplete
, this,
536 // On the browser side we grow |max_written_offset_| monotonically, due to the
537 // unpredictable ordering of plugin side Write and SetLength calls. Match that
539 if (max_written_offset_
< length
)
540 max_written_offset_
= length
;
543 int32_t FileIOResource::OnQueryComplete(scoped_refptr
<QueryOp
> query_op
,
546 DCHECK(state_manager_
.get_pending_operation() ==
547 FileIOStateManager::OPERATION_EXCLUSIVE
);
549 if (result
== PP_OK
) {
550 // This writes the file info into the plugin's PP_FileInfo struct.
551 ppapi::FileInfoToPepperFileInfo(query_op
->file_info(),
555 state_manager_
.SetOperationFinished();
559 int32_t FileIOResource::OnReadComplete(scoped_refptr
<ReadOp
> read_op
,
560 PP_ArrayOutput array_output
,
562 DCHECK(state_manager_
.get_pending_operation() ==
563 FileIOStateManager::OPERATION_READ
);
566 output
.set_pp_array_output(array_output
);
567 if (output
.is_valid())
568 output
.StoreArray(read_op
->buffer(), result
);
570 result
= PP_ERROR_FAILED
;
572 // The read operation failed.
573 result
= PP_ERROR_FAILED
;
575 state_manager_
.SetOperationFinished();
579 void FileIOResource::OnRequestWriteQuotaComplete(
581 scoped_ptr
<char[]> buffer
,
582 int32_t bytes_to_write
,
583 scoped_refptr
<TrackedCallback
> callback
,
585 DCHECK(granted
>= 0);
587 callback
->Run(PP_ERROR_NOQUOTA
);
590 if (open_flags_
& PP_FILEOPENFLAG_APPEND
) {
591 DCHECK_LE(bytes_to_write
, granted
);
592 append_mode_write_amount_
+= bytes_to_write
;
594 DCHECK_LE(offset
+ bytes_to_write
- max_written_offset_
, granted
);
596 int64_t max_offset
= offset
+ bytes_to_write
;
597 if (max_written_offset_
< max_offset
)
598 max_written_offset_
= max_offset
;
601 if (callback
->is_blocking()) {
603 WriteValidated(offset
, buffer
.get(), bytes_to_write
, callback
);
604 DCHECK(result
!= PP_OK_COMPLETIONPENDING
);
605 callback
->Run(result
);
607 bool append
= (open_flags_
& PP_FILEOPENFLAG_APPEND
) != 0;
608 scoped_refptr
<WriteOp
> write_op(new WriteOp(
609 file_holder_
, offset
, buffer
.Pass(), bytes_to_write
, append
));
610 base::PostTaskAndReplyWithResult(
611 PpapiGlobals::Get()->GetFileTaskRunner(),
613 Bind(&FileIOResource::WriteOp::DoWork
, write_op
),
614 RunWhileLocked(Bind(&TrackedCallback::Run
, callback
)));
615 callback
->set_completion_task(Bind(&FileIOResource::OnWriteComplete
, this));
619 void FileIOResource::OnRequestSetLengthQuotaComplete(
621 scoped_refptr
<TrackedCallback
> callback
,
623 DCHECK(granted
>= 0);
625 callback
->Run(PP_ERROR_NOQUOTA
);
629 DCHECK_LE(length
- max_written_offset_
, granted
);
630 if (max_written_offset_
< length
)
631 max_written_offset_
= length
;
632 SetLengthValidated(length
, callback
);
635 int32_t FileIOResource::OnWriteComplete(int32_t result
) {
636 DCHECK(state_manager_
.get_pending_operation() ==
637 FileIOStateManager::OPERATION_WRITE
);
638 // |result| is the return value of WritePlatformFile; -1 indicates failure.
640 result
= PP_ERROR_FAILED
;
642 state_manager_
.SetOperationFinished();
646 void FileIOResource::OnPluginMsgGeneralComplete(
647 scoped_refptr
<TrackedCallback
> callback
,
648 const ResourceMessageReplyParams
& params
) {
649 DCHECK(state_manager_
.get_pending_operation() ==
650 FileIOStateManager::OPERATION_EXCLUSIVE
||
651 state_manager_
.get_pending_operation() ==
652 FileIOStateManager::OPERATION_WRITE
);
653 // End this operation now, so the user's callback can execute another FileIO
654 // operation, assuming there are no other pending operations.
655 state_manager_
.SetOperationFinished();
656 callback
->Run(params
.result());
659 void FileIOResource::OnPluginMsgOpenFileComplete(
660 scoped_refptr
<TrackedCallback
> callback
,
661 const ResourceMessageReplyParams
& params
,
662 PP_Resource quota_file_system
,
663 int64_t max_written_offset
) {
664 DCHECK(state_manager_
.get_pending_operation() ==
665 FileIOStateManager::OPERATION_EXCLUSIVE
);
667 // Release the FileRef resource.
669 int32_t result
= params
.result();
670 if (result
== PP_OK
) {
671 state_manager_
.SetOpenSucceed();
673 if (quota_file_system
) {
674 DCHECK(quota_file_system
== file_system_resource_
->pp_resource());
676 max_written_offset_
= max_written_offset
;
677 file_system_resource_
->AsPPB_FileSystem_API()->OpenQuotaFile(
681 IPC::PlatformFileForTransit transit_file
;
682 if (params
.TakeFileHandleAtIndex(0, &transit_file
)) {
683 file_holder_
= new FileHolder(
684 IPC::PlatformFileForTransitToPlatformFile(transit_file
));
687 // End this operation now, so the user's callback can execute another FileIO
688 // operation, assuming there are no other pending operations.
689 state_manager_
.SetOperationFinished();
690 callback
->Run(result
);
693 void FileIOResource::OnPluginMsgRequestOSFileHandleComplete(
694 scoped_refptr
<TrackedCallback
> callback
,
695 PP_FileHandle
* output_handle
,
696 const ResourceMessageReplyParams
& params
) {
697 DCHECK(state_manager_
.get_pending_operation() ==
698 FileIOStateManager::OPERATION_EXCLUSIVE
);
700 if (!TrackedCallback::IsPending(callback
)) {
701 state_manager_
.SetOperationFinished();
705 int32_t result
= params
.result();
706 IPC::PlatformFileForTransit transit_file
;
707 if (!params
.TakeFileHandleAtIndex(0, &transit_file
))
708 result
= PP_ERROR_FAILED
;
709 *output_handle
= IPC::PlatformFileForTransitToPlatformFile(transit_file
);
711 // End this operation now, so the user's callback can execute another FileIO
712 // operation, assuming there are no other pending operations.
713 state_manager_
.SetOperationFinished();
714 callback
->Run(result
);