Revert 189300
[chromium-blink-merge.git] / content / renderer / pepper / pepper_file_io_host.cc
blobd0fb617c54b5a363db8dc467af64da0128b320d7
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 "content/renderer/pepper/pepper_file_io_host.h"
7 #include "base/bind.h"
8 #include "base/callback_helpers.h"
9 #include "base/files/file_util_proxy.h"
10 #include "ppapi/c/pp_errors.h"
11 #include "ppapi/host/dispatch_host_message.h"
12 #include "ppapi/host/ppapi_host.h"
13 #include "ppapi/proxy/ppapi_messages.h"
14 #include "ppapi/shared_impl/file_type_conversion.h"
15 #include "ppapi/shared_impl/time_conversion.h"
16 #include "ppapi/thunk/enter.h"
17 #include "webkit/fileapi/file_system_callback_dispatcher.h"
18 #include "webkit/plugins/ppapi/file_callbacks.h"
19 #include "webkit/plugins/ppapi/host_globals.h"
20 #include "webkit/plugins/ppapi/ppapi_plugin_instance.h"
21 #include "webkit/plugins/ppapi/ppb_file_ref_impl.h"
22 #include "webkit/plugins/ppapi/quota_file_io.h"
24 namespace content {
26 using ppapi::FileIOStateManager;
27 using ppapi::PPTimeToTime;
28 using ppapi::TimeToPPTime;
29 using ppapi::host::ReplyMessageContext;
30 using ppapi::thunk::EnterResourceNoLock;
31 using ppapi::thunk::PPB_FileRef_API;
32 using webkit::ppapi::PPB_FileRef_Impl;
33 using webkit::ppapi::PluginDelegate;
35 namespace {
37 // The maximum size we'll support reading in one chunk. The renderer process
38 // must allocate a buffer sized according to the request of the plugin. To
39 // keep things from getting out of control, we cap the read size to this value.
40 // This should generally be OK since the API specifies that it may perform a
41 // partial read.
42 static const int32_t kMaxReadSize = 32 * 1024 * 1024; // 32MB
44 typedef base::Callback<void (base::PlatformFileError)> PlatformGeneralCallback;
46 class PlatformGeneralCallbackTranslator
47 : public fileapi::FileSystemCallbackDispatcher {
48 public:
49 explicit PlatformGeneralCallbackTranslator(
50 const PlatformGeneralCallback& callback)
51 : callback_(callback) {}
53 virtual ~PlatformGeneralCallbackTranslator() {}
55 virtual void DidSucceed() OVERRIDE {
56 callback_.Run(base::PLATFORM_FILE_OK);
59 virtual void DidReadMetadata(const base::PlatformFileInfo& file_info,
60 const base::FilePath& platform_path) OVERRIDE {
61 NOTREACHED();
64 virtual void DidCreateSnapshotFile(
65 const base::PlatformFileInfo& file_info,
66 const base::FilePath& platform_path) OVERRIDE {
67 NOTREACHED();
70 virtual void DidReadDirectory(
71 const std::vector<base::FileUtilProxy::Entry>& entries,
72 bool has_more) OVERRIDE {
73 NOTREACHED();
76 virtual void DidOpenFileSystem(const std::string& name,
77 const GURL& root) OVERRIDE {
78 NOTREACHED();
81 virtual void DidFail(base::PlatformFileError error_code) OVERRIDE {
82 callback_.Run(error_code);
85 virtual void DidWrite(int64 bytes, bool complete) OVERRIDE {
86 NOTREACHED();
89 virtual void DidOpenFile(base::PlatformFile file) OVERRIDE {
90 NOTREACHED();
93 private:
94 PlatformGeneralCallback callback_;
97 int32_t ErrorOrByteNumber(int32_t pp_error, int32_t byte_number) {
98 // On the plugin side, some callbacks expect a parameter that means different
99 // things depending on whether is negative or not. We translate for those
100 // callbacks here.
101 return pp_error == PP_OK ? byte_number : pp_error;
104 } // namespace
106 PepperFileIOHost::PepperFileIOHost(RendererPpapiHost* host,
107 PP_Instance instance,
108 PP_Resource resource)
109 : ResourceHost(host->GetPpapiHost(), instance, resource),
110 file_(base::kInvalidPlatformFileValue),
111 file_system_type_(PP_FILESYSTEMTYPE_INVALID),
112 is_running_in_process_(host->IsRunningInProcess()),
113 weak_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) {
114 // TODO(victorhsieh): eliminate plugin_delegate_ as it's no longer needed.
115 webkit::ppapi::PluginInstance* plugin_instance =
116 webkit::ppapi::HostGlobals::Get()->GetInstance(instance);
117 plugin_delegate_ = plugin_instance ? plugin_instance->delegate() : NULL;
120 PepperFileIOHost::~PepperFileIOHost() {
121 OnHostMsgClose(NULL);
124 int32_t PepperFileIOHost::OnResourceMessageReceived(
125 const IPC::Message& msg,
126 ppapi::host::HostMessageContext* context) {
127 IPC_BEGIN_MESSAGE_MAP(PepperFileIOHost, msg)
128 PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_FileIO_Open,
129 OnHostMsgOpen)
130 PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(PpapiHostMsg_FileIO_Query,
131 OnHostMsgQuery)
132 PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_FileIO_Touch,
133 OnHostMsgTouch)
134 PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_FileIO_Read,
135 OnHostMsgRead)
136 PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_FileIO_Write,
137 OnHostMsgWrite)
138 PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_FileIO_SetLength,
139 OnHostMsgSetLength)
140 PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(PpapiHostMsg_FileIO_Flush,
141 OnHostMsgFlush)
142 PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(PpapiHostMsg_FileIO_Close,
143 OnHostMsgClose)
144 PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_FileIO_WillWrite,
145 OnHostMsgWillWrite)
146 PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_FileIO_WillSetLength,
147 OnHostMsgWillSetLength)
148 PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(PpapiHostMsg_FileIO_GetOSFileDescriptor,
149 OnHostMsgGetOSFileDescriptor)
150 IPC_END_MESSAGE_MAP()
151 return PP_ERROR_FAILED;
154 int32_t PepperFileIOHost::OnHostMsgOpen(
155 ppapi::host::HostMessageContext* context,
156 PP_Resource file_ref_resource,
157 int32_t open_flags) {
158 int32_t rv = state_manager_.CheckOperationState(
159 FileIOStateManager::OPERATION_EXCLUSIVE, false);
160 if (rv != PP_OK)
161 return rv;
163 int flags = 0;
164 if (!::ppapi::PepperFileOpenFlagsToPlatformFileFlags(open_flags, &flags))
165 return PP_ERROR_BADARGUMENT;
167 EnterResourceNoLock<PPB_FileRef_API> enter(file_ref_resource, true);
168 if (enter.failed())
169 return PP_ERROR_BADRESOURCE;
171 PPB_FileRef_API* file_ref_api = enter.object();
172 PP_FileSystemType type = file_ref_api->GetFileSystemType();
173 if (type != PP_FILESYSTEMTYPE_LOCALPERSISTENT &&
174 type != PP_FILESYSTEMTYPE_LOCALTEMPORARY &&
175 type != PP_FILESYSTEMTYPE_EXTERNAL)
176 return PP_ERROR_FAILED;
177 file_system_type_ = type;
179 if (!plugin_delegate_)
180 return PP_ERROR_FAILED;
182 PPB_FileRef_Impl* file_ref = static_cast<PPB_FileRef_Impl*>(file_ref_api);
183 if (file_ref->HasValidFileSystem()) {
184 file_system_url_ = file_ref->GetFileSystemURL();
185 if (!plugin_delegate_->AsyncOpenFileSystemURL(
186 file_system_url_, flags,
187 base::Bind(
188 &PepperFileIOHost::ExecutePlatformOpenFileSystemURLCallback,
189 weak_factory_.GetWeakPtr(),
190 context->MakeReplyMessageContext())))
191 return PP_ERROR_FAILED;
192 } else {
193 if (file_system_type_ != PP_FILESYSTEMTYPE_EXTERNAL)
194 return PP_ERROR_FAILED;
195 if (!plugin_delegate_->AsyncOpenFile(
196 file_ref->GetSystemPath(), flags,
197 base::Bind(&PepperFileIOHost::ExecutePlatformOpenFileCallback,
198 weak_factory_.GetWeakPtr(),
199 context->MakeReplyMessageContext())))
200 return PP_ERROR_FAILED;
203 state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_EXCLUSIVE);
204 return PP_OK_COMPLETIONPENDING;
207 int32_t PepperFileIOHost::OnHostMsgQuery(
208 ppapi::host::HostMessageContext* context) {
209 int32_t rv = state_manager_.CheckOperationState(
210 FileIOStateManager::OPERATION_EXCLUSIVE, true);
211 if (rv != PP_OK)
212 return rv;
214 if (!plugin_delegate_)
215 return PP_ERROR_FAILED;
217 if (!base::FileUtilProxy::GetFileInfoFromPlatformFile(
218 plugin_delegate_->GetFileThreadMessageLoopProxy(), file_,
219 base::Bind(&PepperFileIOHost::ExecutePlatformQueryCallback,
220 weak_factory_.GetWeakPtr(),
221 context->MakeReplyMessageContext())))
222 return PP_ERROR_FAILED;
224 state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_EXCLUSIVE);
225 return PP_OK_COMPLETIONPENDING;
228 int32_t PepperFileIOHost::OnHostMsgTouch(
229 ppapi::host::HostMessageContext* context,
230 PP_Time last_access_time,
231 PP_Time last_modified_time) {
232 int32_t rv = state_manager_.CheckOperationState(
233 FileIOStateManager::OPERATION_EXCLUSIVE, true);
234 if (rv != PP_OK)
235 return rv;
237 if (!plugin_delegate_)
238 return PP_ERROR_FAILED;
240 if (file_system_type_ != PP_FILESYSTEMTYPE_EXTERNAL) {
241 if (!plugin_delegate_->Touch(
242 file_system_url_,
243 PPTimeToTime(last_access_time),
244 PPTimeToTime(last_modified_time),
245 new PlatformGeneralCallbackTranslator(
246 base::Bind(&PepperFileIOHost::ExecutePlatformGeneralCallback,
247 weak_factory_.GetWeakPtr(),
248 context->MakeReplyMessageContext()))))
249 return PP_ERROR_FAILED;
250 state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_EXCLUSIVE);
251 return PP_OK_COMPLETIONPENDING;
254 // TODO(nhiroki): fix a failure of FileIO.Touch for an external filesystem on
255 // Mac and Linux due to sandbox restrictions (http://crbug.com/101128).
256 if (!base::FileUtilProxy::Touch(
257 plugin_delegate_->GetFileThreadMessageLoopProxy(),
258 file_, PPTimeToTime(last_access_time),
259 PPTimeToTime(last_modified_time),
260 base::Bind(&PepperFileIOHost::ExecutePlatformGeneralCallback,
261 weak_factory_.GetWeakPtr(),
262 context->MakeReplyMessageContext())))
263 return PP_ERROR_FAILED;
265 state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_EXCLUSIVE);
266 return PP_OK_COMPLETIONPENDING;
269 int32_t PepperFileIOHost::OnHostMsgRead(
270 ppapi::host::HostMessageContext* context,
271 int64_t offset,
272 int32_t max_read_length) {
273 int32_t rv = state_manager_.CheckOperationState(
274 FileIOStateManager::OPERATION_READ, true);
275 if (rv != PP_OK)
276 return rv;
278 // Validate max_read_length before allocating below. This value is coming from
279 // the untrusted plugin.
280 if (max_read_length < 0) {
281 ReplyMessageContext reply_context = context->MakeReplyMessageContext();
282 reply_context.params.set_result(PP_ERROR_FAILED);
283 host()->SendReply(reply_context,
284 PpapiPluginMsg_FileIO_ReadReply(std::string()));
285 return PP_OK_COMPLETIONPENDING;
288 if (!plugin_delegate_)
289 return PP_ERROR_FAILED;
291 if (!base::FileUtilProxy::Read(
292 plugin_delegate_->GetFileThreadMessageLoopProxy(), file_, offset,
293 max_read_length,
294 base::Bind(&PepperFileIOHost::ExecutePlatformReadCallback,
295 weak_factory_.GetWeakPtr(),
296 context->MakeReplyMessageContext())))
297 return PP_ERROR_FAILED;
299 state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_READ);
300 return PP_OK_COMPLETIONPENDING;
303 int32_t PepperFileIOHost::OnHostMsgWrite(
304 ppapi::host::HostMessageContext* context,
305 int64_t offset,
306 const std::string& buffer) {
307 int32_t rv = state_manager_.CheckOperationState(
308 FileIOStateManager::OPERATION_WRITE, true);
309 if (rv != PP_OK)
310 return rv;
312 if (quota_file_io_.get()) {
313 if (!quota_file_io_->Write(
314 offset, buffer.c_str(), buffer.size(),
315 base::Bind(&PepperFileIOHost::ExecutePlatformWriteCallback,
316 weak_factory_.GetWeakPtr(),
317 context->MakeReplyMessageContext())))
318 return PP_ERROR_FAILED;
319 } else {
320 if (!plugin_delegate_)
321 return PP_ERROR_FAILED;
323 if (!base::FileUtilProxy::Write(
324 plugin_delegate_->GetFileThreadMessageLoopProxy(), file_, offset,
325 buffer.c_str(), buffer.size(),
326 base::Bind(&PepperFileIOHost::ExecutePlatformWriteCallback,
327 weak_factory_.GetWeakPtr(),
328 context->MakeReplyMessageContext())))
329 return PP_ERROR_FAILED;
332 state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_WRITE);
333 return PP_OK_COMPLETIONPENDING;
336 int32_t PepperFileIOHost::OnHostMsgSetLength(
337 ppapi::host::HostMessageContext* context,
338 int64_t length) {
339 int32_t rv = state_manager_.CheckOperationState(
340 FileIOStateManager::OPERATION_EXCLUSIVE, true);
341 if (rv != PP_OK)
342 return rv;
344 if (!plugin_delegate_)
345 return PP_ERROR_FAILED;
347 if (file_system_type_ != PP_FILESYSTEMTYPE_EXTERNAL) {
348 if (!plugin_delegate_->SetLength(
349 file_system_url_, length,
350 new PlatformGeneralCallbackTranslator(
351 base::Bind(&PepperFileIOHost::ExecutePlatformGeneralCallback,
352 weak_factory_.GetWeakPtr(),
353 context->MakeReplyMessageContext()))))
354 return PP_ERROR_FAILED;
355 } else {
356 // TODO(nhiroki): fix a failure of FileIO.SetLength for an external
357 // filesystem on Mac due to sandbox restrictions (http://crbug.com/156077).
358 if (!base::FileUtilProxy::Truncate(
359 plugin_delegate_->GetFileThreadMessageLoopProxy(), file_, length,
360 base::Bind(&PepperFileIOHost::ExecutePlatformGeneralCallback,
361 weak_factory_.GetWeakPtr(),
362 context->MakeReplyMessageContext())))
363 return PP_ERROR_FAILED;
366 state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_EXCLUSIVE);
367 return PP_OK_COMPLETIONPENDING;
370 int32_t PepperFileIOHost::OnHostMsgFlush(
371 ppapi::host::HostMessageContext* context) {
372 int32_t rv = state_manager_.CheckOperationState(
373 FileIOStateManager::OPERATION_EXCLUSIVE, true);
374 if (rv != PP_OK)
375 return rv;
377 if (!plugin_delegate_)
378 return PP_ERROR_FAILED;
380 if (!base::FileUtilProxy::Flush(
381 plugin_delegate_->GetFileThreadMessageLoopProxy(), file_,
382 base::Bind(&PepperFileIOHost::ExecutePlatformGeneralCallback,
383 weak_factory_.GetWeakPtr(),
384 context->MakeReplyMessageContext())))
385 return PP_ERROR_FAILED;
387 state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_EXCLUSIVE);
388 return PP_OK_COMPLETIONPENDING;
391 int32_t PepperFileIOHost::OnHostMsgClose(
392 ppapi::host::HostMessageContext* context) {
393 if (file_ != base::kInvalidPlatformFileValue && plugin_delegate_) {
394 base::FileUtilProxy::Close(
395 plugin_delegate_->GetFileThreadMessageLoopProxy(),
396 file_,
397 base::ResetAndReturn(&notify_close_file_callback_));
398 file_ = base::kInvalidPlatformFileValue;
399 quota_file_io_.reset();
401 return PP_OK;
404 int32_t PepperFileIOHost::OnHostMsgWillWrite(
405 ppapi::host::HostMessageContext* context,
406 int64_t offset,
407 int32_t bytes_to_write) {
408 int32_t rv = state_manager_.CheckOperationState(
409 FileIOStateManager::OPERATION_EXCLUSIVE, true);
410 if (rv != PP_OK)
411 return rv;
413 if (!quota_file_io_.get())
414 return PP_OK;
416 if (!quota_file_io_->WillWrite(
417 offset, bytes_to_write,
418 base::Bind(&PepperFileIOHost::ExecutePlatformWillWriteCallback,
419 weak_factory_.GetWeakPtr(),
420 context->MakeReplyMessageContext())))
421 return PP_ERROR_FAILED;
423 state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_EXCLUSIVE);
424 return PP_OK_COMPLETIONPENDING;
427 int32_t PepperFileIOHost::OnHostMsgWillSetLength(
428 ppapi::host::HostMessageContext* context,
429 int64_t length) {
430 int32_t rv = state_manager_.CheckOperationState(
431 FileIOStateManager::OPERATION_EXCLUSIVE, true);
432 if (rv != PP_OK)
433 return rv;
435 if (!quota_file_io_.get())
436 return PP_OK;
438 if (!quota_file_io_->WillSetLength(
439 length,
440 base::Bind(&PepperFileIOHost::ExecutePlatformGeneralCallback,
441 weak_factory_.GetWeakPtr(),
442 context->MakeReplyMessageContext())))
443 return PP_ERROR_FAILED;
445 state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_EXCLUSIVE);
446 return PP_OK_COMPLETIONPENDING;
449 int32_t PepperFileIOHost::OnHostMsgGetOSFileDescriptor(
450 ppapi::host::HostMessageContext* context) {
451 if (!is_running_in_process_)
452 return PP_ERROR_FAILED;
453 int32_t fd =
454 #if defined(OS_POSIX)
455 file_;
456 #elif defined(OS_WIN)
457 reinterpret_cast<uintptr_t>(file_);
458 #else
459 -1; // Platform not supported.
460 #endif
461 // TODO(victorhsieh): Pass the file handle in the reply params once this works
462 // in-process.
463 host()->SendReply(context->MakeReplyMessageContext(),
464 PpapiPluginMsg_FileIO_GetOSFileDescriptorReply(fd));
465 return PP_OK_COMPLETIONPENDING;
468 void PepperFileIOHost::ExecutePlatformGeneralCallback(
469 ppapi::host::ReplyMessageContext reply_context,
470 base::PlatformFileError error_code) {
471 reply_context.params.set_result(
472 ::ppapi::PlatformFileErrorToPepperError(error_code));
473 host()->SendReply(reply_context, PpapiPluginMsg_FileIO_GeneralReply());
474 state_manager_.SetOperationFinished();
477 void PepperFileIOHost::ExecutePlatformOpenFileCallback(
478 ppapi::host::ReplyMessageContext reply_context,
479 base::PlatformFileError error_code,
480 base::PassPlatformFile file) {
481 int32_t pp_error = ::ppapi::PlatformFileErrorToPepperError(error_code);
482 if (pp_error == PP_OK)
483 state_manager_.SetOpenSucceed();
485 DCHECK(file_ == base::kInvalidPlatformFileValue);
486 file_ = file.ReleaseValue();
488 DCHECK(!quota_file_io_.get());
489 if (file_ != base::kInvalidPlatformFileValue &&
490 (file_system_type_ == PP_FILESYSTEMTYPE_LOCALTEMPORARY ||
491 file_system_type_ == PP_FILESYSTEMTYPE_LOCALPERSISTENT)) {
492 quota_file_io_.reset(new webkit::ppapi::QuotaFileIO(
493 pp_instance(), file_, file_system_url_, file_system_type_));
496 reply_context.params.set_result(pp_error);
497 host()->SendReply(reply_context, PpapiPluginMsg_FileIO_OpenReply());
498 state_manager_.SetOperationFinished();
501 void PepperFileIOHost::ExecutePlatformOpenFileSystemURLCallback(
502 ppapi::host::ReplyMessageContext reply_context,
503 base::PlatformFileError error_code,
504 base::PassPlatformFile file,
505 const PluginDelegate::NotifyCloseFileCallback& callback) {
506 if (error_code == base::PLATFORM_FILE_OK)
507 notify_close_file_callback_ = callback;
508 ExecutePlatformOpenFileCallback(reply_context, error_code, file);
511 void PepperFileIOHost::ExecutePlatformQueryCallback(
512 ppapi::host::ReplyMessageContext reply_context,
513 base::PlatformFileError error_code,
514 const base::PlatformFileInfo& file_info) {
515 PP_FileInfo pp_info;
516 pp_info.size = file_info.size;
517 pp_info.creation_time = TimeToPPTime(file_info.creation_time);
518 pp_info.last_access_time = TimeToPPTime(file_info.last_accessed);
519 pp_info.last_modified_time = TimeToPPTime(file_info.last_modified);
520 pp_info.system_type = file_system_type_;
521 if (file_info.is_directory)
522 pp_info.type = PP_FILETYPE_DIRECTORY;
523 else
524 pp_info.type = PP_FILETYPE_REGULAR;
526 int32_t pp_error = ::ppapi::PlatformFileErrorToPepperError(error_code);
527 reply_context.params.set_result(pp_error);
528 host()->SendReply(reply_context,
529 PpapiPluginMsg_FileIO_QueryReply(pp_info));
530 state_manager_.SetOperationFinished();
533 void PepperFileIOHost::ExecutePlatformReadCallback(
534 ppapi::host::ReplyMessageContext reply_context,
535 base::PlatformFileError error_code,
536 const char* data, int bytes_read) {
537 int32_t pp_error = ::ppapi::PlatformFileErrorToPepperError(error_code);
539 // Only send the amount of data in the string that was actually read.
540 std::string buffer;
541 if (pp_error == PP_OK)
542 buffer.append(data, bytes_read);
543 reply_context.params.set_result(ErrorOrByteNumber(pp_error, bytes_read));
544 host()->SendReply(reply_context, PpapiPluginMsg_FileIO_ReadReply(buffer));
545 state_manager_.SetOperationFinished();
548 void PepperFileIOHost::ExecutePlatformWriteCallback(
549 ppapi::host::ReplyMessageContext reply_context,
550 base::PlatformFileError error_code,
551 int bytes_written) {
552 int32_t pp_error = ::ppapi::PlatformFileErrorToPepperError(error_code);
553 reply_context.params.set_result(ErrorOrByteNumber(pp_error, bytes_written));
554 host()->SendReply(reply_context, PpapiPluginMsg_FileIO_GeneralReply());
555 state_manager_.SetOperationFinished();
558 void PepperFileIOHost::ExecutePlatformWillWriteCallback(
559 ppapi::host::ReplyMessageContext reply_context,
560 base::PlatformFileError error_code,
561 int bytes_written) {
562 // On the plugin side, the callback expects a parameter with different meaning
563 // depends on whether is negative or not. It is the result here. We translate
564 // for the callback.
565 int32_t pp_error = ::ppapi::PlatformFileErrorToPepperError(error_code);
566 reply_context.params.set_result(ErrorOrByteNumber(pp_error, bytes_written));
567 host()->SendReply(reply_context, PpapiPluginMsg_FileIO_GeneralReply());
568 state_manager_.SetOperationFinished();
571 } // namespace content