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. 4 5 #include "content/renderer/pepper/pepper_file_io_host.h" 6 7 #include "base/bind.h" 8 #include "base/callback.h" 9 #include "base/callback_helpers.h" 10 #include "base/command_line.h" 11 #include "base/files/file_util_proxy.h" 12 #include "content/child/child_thread.h" 13 #include "content/child/fileapi/file_system_dispatcher.h" 14 #include "content/child/quota_dispatcher.h" 15 #include "content/common/fileapi/file_system_messages.h" 16 #include "content/common/view_messages.h" 17 #include "content/public/common/content_client.h" 18 #include "content/public/renderer/content_renderer_client.h" 19 #include "content/renderer/pepper/host_globals.h" 20 #include "content/renderer/pepper/pepper_plugin_instance_impl.h" 21 #include "content/renderer/pepper/ppb_file_ref_impl.h" 22 #include "content/renderer/pepper/quota_file_io.h" 23 #include "content/renderer/render_thread_impl.h" 24 #include "ppapi/c/pp_errors.h" 25 #include "ppapi/c/ppb_file_io.h" 26 #include "ppapi/host/dispatch_host_message.h" 27 #include "ppapi/host/ppapi_host.h" 28 #include "ppapi/proxy/ppapi_messages.h" 29 #include "ppapi/shared_impl/file_type_conversion.h" 30 #include "ppapi/shared_impl/time_conversion.h" 31 #include "ppapi/thunk/enter.h" 32 #include "third_party/WebKit/public/web/WebPluginContainer.h" 33 34 namespace content { 35 36 using ppapi::FileIOStateManager; 37 using ppapi::PPTimeToTime; 38 using ppapi::host::ReplyMessageContext; 39 using ppapi::thunk::EnterResourceNoLock; 40 using ppapi::thunk::PPB_FileRef_API; 41 42 namespace { 43 44 typedef base::Callback<void (base::PlatformFileError)> PlatformGeneralCallback; 45 46 int32_t ErrorOrByteNumber(int32_t pp_error, int32_t byte_number) { 47 // On the plugin side, some callbacks expect a parameter that means different 48 // things depending on whether is negative or not. We translate for those 49 // callbacks here. 50 return pp_error == PP_OK ? byte_number : pp_error; 51 } 52 53 class QuotaCallbackTranslator : public QuotaDispatcher::Callback { 54 public: 55 typedef QuotaFileIO::Delegate::AvailableSpaceCallback PluginCallback; 56 explicit QuotaCallbackTranslator(const PluginCallback& cb) : callback_(cb) {} 57 virtual void DidQueryStorageUsageAndQuota(int64 usage, int64 quota) OVERRIDE { 58 callback_.Run(std::max(static_cast<int64>(0), quota - usage)); 59 } 60 virtual void DidGrantStorageQuota(int64 granted_quota) OVERRIDE { 61 NOTREACHED(); 62 } 63 virtual void DidFail(quota::QuotaStatusCode error) OVERRIDE { 64 callback_.Run(0); 65 } 66 private: 67 PluginCallback callback_; 68 }; 69 70 class QuotaFileIODelegate : public QuotaFileIO::Delegate { 71 public: 72 QuotaFileIODelegate() {} 73 virtual ~QuotaFileIODelegate() {} 74 75 virtual void QueryAvailableSpace( 76 const GURL& origin, 77 quota::StorageType type, 78 const AvailableSpaceCallback& callback) OVERRIDE { 79 ChildThread::current()->quota_dispatcher()->QueryStorageUsageAndQuota( 80 origin, type, new QuotaCallbackTranslator(callback)); 81 } 82 virtual void WillUpdateFile(const GURL& file_path) OVERRIDE { 83 ChildThread::current()->Send(new FileSystemHostMsg_WillUpdate(file_path)); 84 } 85 virtual void DidUpdateFile(const GURL& file_path, int64_t delta) OVERRIDE { 86 ChildThread::current()->Send(new FileSystemHostMsg_DidUpdate( 87 file_path, delta)); 88 } 89 virtual scoped_refptr<base::MessageLoopProxy> 90 GetFileThreadMessageLoopProxy() OVERRIDE { 91 return RenderThreadImpl::current()->GetFileThreadMessageLoopProxy(); 92 } 93 }; 94 95 typedef base::Callback< 96 void (base::PlatformFileError error, 97 base::PassPlatformFile file, 98 quota::QuotaLimitType quota_policy, 99 const PepperFileIOHost::NotifyCloseFileCallback& close_file_callback)> 100 AsyncOpenFileSystemURLCallback; 101 102 void DoNotifyCloseFile(int file_open_id, base::PlatformFileError error) { 103 ChildThread::current()->file_system_dispatcher()->NotifyCloseFile( 104 file_open_id); 105 } 106 107 void DidOpenFileSystemURL(const AsyncOpenFileSystemURLCallback& callback, 108 base::PlatformFile file, 109 int file_open_id, 110 quota::QuotaLimitType quota_policy) { 111 callback.Run(base::PLATFORM_FILE_OK, 112 base::PassPlatformFile(&file), 113 quota_policy, 114 base::Bind(&DoNotifyCloseFile, file_open_id)); 115 // Make sure we won't leak file handle if the requester has died. 116 if (file != base::kInvalidPlatformFileValue) { 117 base::FileUtilProxy::Close( 118 RenderThreadImpl::current()->GetFileThreadMessageLoopProxy().get(), 119 file, 120 base::Bind(&DoNotifyCloseFile, file_open_id)); 121 } 122 } 123 124 void DidFailOpenFileSystemURL(const AsyncOpenFileSystemURLCallback& callback, 125 base::PlatformFileError error_code) { 126 base::PlatformFile invalid_file = base::kInvalidPlatformFileValue; 127 callback.Run(error_code, 128 base::PassPlatformFile(&invalid_file), 129 quota::kQuotaLimitTypeUnknown, 130 PepperFileIOHost::NotifyCloseFileCallback()); 131 } 132 133 } // namespace 134 135 PepperFileIOHost::PepperFileIOHost(RendererPpapiHost* host, 136 PP_Instance instance, 137 PP_Resource resource) 138 : ResourceHost(host->GetPpapiHost(), instance, resource), 139 renderer_ppapi_host_(host), 140 file_(base::kInvalidPlatformFileValue), 141 file_system_type_(PP_FILESYSTEMTYPE_INVALID), 142 quota_policy_(quota::kQuotaLimitTypeUnknown), 143 is_running_in_process_(host->IsRunningInProcess()), 144 open_flags_(0), 145 weak_factory_(this), 146 routing_id_(RenderThreadImpl::current()->GenerateRoutingID()) { 147 ChildThread::current()->AddRoute(routing_id_, this); 148 } 149 150 PepperFileIOHost::~PepperFileIOHost() { 151 OnHostMsgClose(NULL); 152 ChildThread::current()->RemoveRoute(routing_id_); 153 } 154 155 int32_t PepperFileIOHost::OnResourceMessageReceived( 156 const IPC::Message& msg, 157 ppapi::host::HostMessageContext* context) { 158 IPC_BEGIN_MESSAGE_MAP(PepperFileIOHost, msg) 159 PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_FileIO_Open, 160 OnHostMsgOpen) 161 PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_FileIO_Touch, 162 OnHostMsgTouch) 163 PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_FileIO_Write, 164 OnHostMsgWrite) 165 PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_FileIO_SetLength, 166 OnHostMsgSetLength) 167 PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(PpapiHostMsg_FileIO_Flush, 168 OnHostMsgFlush) 169 PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(PpapiHostMsg_FileIO_Close, 170 OnHostMsgClose) 171 PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_FileIO_WillWrite, 172 OnHostMsgWillWrite) 173 PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_FileIO_WillSetLength, 174 OnHostMsgWillSetLength) 175 PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(PpapiHostMsg_FileIO_GetOSFileDescriptor, 176 OnHostMsgGetOSFileDescriptor) 177 PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(PpapiHostMsg_FileIO_RequestOSFileHandle, 178 OnHostMsgRequestOSFileHandle) 179 IPC_END_MESSAGE_MAP() 180 return PP_ERROR_FAILED; 181 } 182 183 bool PepperFileIOHost::OnMessageReceived(const IPC::Message& msg) { 184 bool handled = true; 185 IPC_BEGIN_MESSAGE_MAP(PepperFileIOHost, msg) 186 IPC_MESSAGE_HANDLER(ViewMsg_AsyncOpenPepperFile_ACK, OnAsyncFileOpened) 187 IPC_MESSAGE_UNHANDLED(handled = false) 188 IPC_END_MESSAGE_MAP() 189 return handled; 190 } 191 192 void PepperFileIOHost::OnAsyncFileOpened( 193 base::PlatformFileError error_code, 194 IPC::PlatformFileForTransit file_for_transit, 195 int message_id) { 196 AsyncOpenFileCallback* callback = 197 pending_async_open_files_.Lookup(message_id); 198 DCHECK(callback); 199 pending_async_open_files_.Remove(message_id); 200 201 base::PlatformFile file = 202 IPC::PlatformFileForTransitToPlatformFile(file_for_transit); 203 callback->Run(error_code, base::PassPlatformFile(&file)); 204 // Make sure we won't leak file handle if the requester has died. 205 if (file != base::kInvalidPlatformFileValue) { 206 base::FileUtilProxy::Close( 207 RenderThreadImpl::current()->GetFileThreadMessageLoopProxy().get(), 208 file, 209 base::FileUtilProxy::StatusCallback()); 210 } 211 delete callback; 212 } 213 214 int32_t PepperFileIOHost::OnHostMsgOpen( 215 ppapi::host::HostMessageContext* context, 216 PP_Resource file_ref_resource, 217 int32_t open_flags) { 218 int32_t rv = state_manager_.CheckOperationState( 219 FileIOStateManager::OPERATION_EXCLUSIVE, false); 220 if (rv != PP_OK) 221 return rv; 222 223 // TODO(tommycli): Eventually just pass the Pepper flags straight to the 224 // FileSystemDispatcher so it can handle doing the security check. 225 int platform_file_flags = 0; 226 open_flags_ = open_flags; 227 if (!ppapi::PepperFileOpenFlagsToPlatformFileFlags(open_flags, 228 &platform_file_flags)) { 229 return PP_ERROR_BADARGUMENT; 230 } 231 232 EnterResourceNoLock<PPB_FileRef_API> enter(file_ref_resource, true); 233 if (enter.failed()) 234 return PP_ERROR_BADRESOURCE; 235 236 PPB_FileRef_API* file_ref_api = enter.object(); 237 PP_FileSystemType type = file_ref_api->GetFileSystemType(); 238 if (type != PP_FILESYSTEMTYPE_LOCALPERSISTENT && 239 type != PP_FILESYSTEMTYPE_LOCALTEMPORARY && 240 type != PP_FILESYSTEMTYPE_EXTERNAL && 241 type != PP_FILESYSTEMTYPE_ISOLATED) 242 return PP_ERROR_FAILED; 243 file_system_type_ = type; 244 245 PPB_FileRef_Impl* file_ref = static_cast<PPB_FileRef_Impl*>(file_ref_api); 246 if (file_ref->HasValidFileSystem()) { 247 file_system_url_ = file_ref->GetFileSystemURL(); 248 249 FileSystemDispatcher* file_system_dispatcher = 250 ChildThread::current()->file_system_dispatcher(); 251 AsyncOpenFileSystemURLCallback callback = base::Bind( 252 &PepperFileIOHost::ExecutePlatformOpenFileSystemURLCallback, 253 weak_factory_.GetWeakPtr(), 254 context->MakeReplyMessageContext()); 255 file_system_dispatcher->OpenFile( 256 file_system_url_, platform_file_flags, 257 base::Bind(&DidOpenFileSystemURL, callback), 258 base::Bind(&DidFailOpenFileSystemURL, callback)); 259 } else { 260 if (file_system_type_ != PP_FILESYSTEMTYPE_EXTERNAL) 261 return PP_ERROR_FAILED; 262 int message_id = pending_async_open_files_.Add(new AsyncOpenFileCallback( 263 base::Bind(&PepperFileIOHost::ExecutePlatformOpenFileCallback, 264 weak_factory_.GetWeakPtr(), 265 context->MakeReplyMessageContext()))); 266 RenderThreadImpl::current()->Send(new ViewHostMsg_AsyncOpenPepperFile( 267 routing_id_, file_ref->GetSystemPath(), open_flags, message_id)); 268 } 269 270 state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_EXCLUSIVE); 271 return PP_OK_COMPLETIONPENDING; 272 } 273 274 int32_t PepperFileIOHost::OnHostMsgTouch( 275 ppapi::host::HostMessageContext* context, 276 PP_Time last_access_time, 277 PP_Time last_modified_time) { 278 int32_t rv = state_manager_.CheckOperationState( 279 FileIOStateManager::OPERATION_EXCLUSIVE, true); 280 if (rv != PP_OK) 281 return rv; 282 283 if (file_system_type_ != PP_FILESYSTEMTYPE_EXTERNAL) { 284 FileSystemDispatcher* file_system_dispatcher = 285 ChildThread::current()->file_system_dispatcher(); 286 file_system_dispatcher->TouchFile( 287 file_system_url_, 288 PPTimeToTime(last_access_time), 289 PPTimeToTime(last_modified_time), 290 base::Bind(&PepperFileIOHost::ExecutePlatformGeneralCallback, 291 weak_factory_.GetWeakPtr(), 292 context->MakeReplyMessageContext())); 293 state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_EXCLUSIVE); 294 return PP_OK_COMPLETIONPENDING; 295 } 296 297 // TODO(nhiroki): fix a failure of FileIO.Touch for an external filesystem on 298 // Mac and Linux due to sandbox restrictions (http://crbug.com/101128). 299 if (!base::FileUtilProxy::Touch( 300 RenderThreadImpl::current()->GetFileThreadMessageLoopProxy().get(), 301 file_, 302 PPTimeToTime(last_access_time), 303 PPTimeToTime(last_modified_time), 304 base::Bind(&PepperFileIOHost::ExecutePlatformGeneralCallback, 305 weak_factory_.GetWeakPtr(), 306 context->MakeReplyMessageContext()))) 307 return PP_ERROR_FAILED; 308 309 state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_EXCLUSIVE); 310 return PP_OK_COMPLETIONPENDING; 311 } 312 313 int32_t PepperFileIOHost::OnHostMsgWrite( 314 ppapi::host::HostMessageContext* context, 315 int64_t offset, 316 const std::string& buffer) { 317 int32_t rv = state_manager_.CheckOperationState( 318 FileIOStateManager::OPERATION_WRITE, true); 319 if (rv != PP_OK) 320 return rv; 321 322 if (quota_file_io_) { 323 if (!quota_file_io_->Write( 324 offset, buffer.c_str(), buffer.size(), 325 base::Bind(&PepperFileIOHost::ExecutePlatformWriteCallback, 326 weak_factory_.GetWeakPtr(), 327 context->MakeReplyMessageContext()))) 328 return PP_ERROR_FAILED; 329 } else { 330 if (!base::FileUtilProxy::Write( 331 RenderThreadImpl::current()->GetFileThreadMessageLoopProxy().get(), 332 file_, 333 offset, 334 buffer.c_str(), 335 buffer.size(), 336 base::Bind(&PepperFileIOHost::ExecutePlatformWriteCallback, 337 weak_factory_.GetWeakPtr(), 338 context->MakeReplyMessageContext()))) 339 return PP_ERROR_FAILED; 340 } 341 342 state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_WRITE); 343 return PP_OK_COMPLETIONPENDING; 344 } 345 346 int32_t PepperFileIOHost::OnHostMsgSetLength( 347 ppapi::host::HostMessageContext* context, 348 int64_t length) { 349 int32_t rv = state_manager_.CheckOperationState( 350 FileIOStateManager::OPERATION_EXCLUSIVE, true); 351 if (rv != PP_OK) 352 return rv; 353 354 if (file_system_type_ != PP_FILESYSTEMTYPE_EXTERNAL) { 355 FileSystemDispatcher* file_system_dispatcher = 356 ChildThread::current()->file_system_dispatcher(); 357 file_system_dispatcher->Truncate( 358 file_system_url_, length, NULL, 359 base::Bind(&PepperFileIOHost::ExecutePlatformGeneralCallback, 360 weak_factory_.GetWeakPtr(), 361 context->MakeReplyMessageContext())); 362 } else { 363 // TODO(nhiroki): fix a failure of FileIO.SetLength for an external 364 // filesystem on Mac due to sandbox restrictions (http://crbug.com/156077). 365 if (!base::FileUtilProxy::Truncate( 366 RenderThreadImpl::current()->GetFileThreadMessageLoopProxy().get(), 367 file_, 368 length, 369 base::Bind(&PepperFileIOHost::ExecutePlatformGeneralCallback, 370 weak_factory_.GetWeakPtr(), 371 context->MakeReplyMessageContext()))) 372 return PP_ERROR_FAILED; 373 } 374 375 state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_EXCLUSIVE); 376 return PP_OK_COMPLETIONPENDING; 377 } 378 379 int32_t PepperFileIOHost::OnHostMsgFlush( 380 ppapi::host::HostMessageContext* context) { 381 int32_t rv = state_manager_.CheckOperationState( 382 FileIOStateManager::OPERATION_EXCLUSIVE, true); 383 if (rv != PP_OK) 384 return rv; 385 386 if (!base::FileUtilProxy::Flush( 387 RenderThreadImpl::current()->GetFileThreadMessageLoopProxy().get(), 388 file_, 389 base::Bind(&PepperFileIOHost::ExecutePlatformGeneralCallback, 390 weak_factory_.GetWeakPtr(), 391 context->MakeReplyMessageContext()))) 392 return PP_ERROR_FAILED; 393 394 state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_EXCLUSIVE); 395 return PP_OK_COMPLETIONPENDING; 396 } 397 398 int32_t PepperFileIOHost::OnHostMsgClose( 399 ppapi::host::HostMessageContext* context) { 400 if (file_ != base::kInvalidPlatformFileValue) { 401 base::FileUtilProxy::Close( 402 RenderThreadImpl::current()->GetFileThreadMessageLoopProxy().get(), 403 file_, 404 base::ResetAndReturn(¬ify_close_file_callback_)); 405 file_ = base::kInvalidPlatformFileValue; 406 quota_file_io_.reset(); 407 } 408 return PP_OK; 409 } 410 411 int32_t PepperFileIOHost::OnHostMsgWillWrite( 412 ppapi::host::HostMessageContext* context, 413 int64_t offset, 414 int32_t bytes_to_write) { 415 int32_t rv = state_manager_.CheckOperationState( 416 FileIOStateManager::OPERATION_EXCLUSIVE, true); 417 if (rv != PP_OK) 418 return rv; 419 420 if (!quota_file_io_) 421 return PP_OK; 422 423 if (!quota_file_io_->WillWrite( 424 offset, bytes_to_write, 425 base::Bind(&PepperFileIOHost::ExecutePlatformWriteCallback, 426 weak_factory_.GetWeakPtr(), 427 context->MakeReplyMessageContext()))) 428 return PP_ERROR_FAILED; 429 430 state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_EXCLUSIVE); 431 return PP_OK_COMPLETIONPENDING; 432 } 433 434 int32_t PepperFileIOHost::OnHostMsgWillSetLength( 435 ppapi::host::HostMessageContext* context, 436 int64_t length) { 437 int32_t rv = state_manager_.CheckOperationState( 438 FileIOStateManager::OPERATION_EXCLUSIVE, true); 439 if (rv != PP_OK) 440 return rv; 441 442 if (!quota_file_io_) 443 return PP_OK; 444 445 if (!quota_file_io_->WillSetLength( 446 length, 447 base::Bind(&PepperFileIOHost::ExecutePlatformGeneralCallback, 448 weak_factory_.GetWeakPtr(), 449 context->MakeReplyMessageContext()))) 450 return PP_ERROR_FAILED; 451 452 state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_EXCLUSIVE); 453 return PP_OK_COMPLETIONPENDING; 454 } 455 456 int32_t PepperFileIOHost::OnHostMsgRequestOSFileHandle( 457 ppapi::host::HostMessageContext* context) { 458 if (!is_running_in_process_ && 459 quota_policy_ != quota::kQuotaLimitTypeUnlimited) 460 return PP_ERROR_FAILED; 461 462 // Whitelist to make it privately accessible. 463 if (!GetContentClient()->renderer()->IsPluginAllowedToCallRequestOSFileHandle( 464 renderer_ppapi_host_->GetContainerForInstance(pp_instance()))) 465 return PP_ERROR_NOACCESS; 466 467 IPC::PlatformFileForTransit file = 468 renderer_ppapi_host_->ShareHandleWithRemote(file_, false); 469 if (file == IPC::InvalidPlatformFileForTransit()) 470 return PP_ERROR_FAILED; 471 ppapi::host::ReplyMessageContext reply_context = 472 context->MakeReplyMessageContext(); 473 ppapi::proxy::SerializedHandle file_handle; 474 file_handle.set_file_handle(file, open_flags_); 475 reply_context.params.AppendHandle(file_handle); 476 host()->SendReply(reply_context, 477 PpapiPluginMsg_FileIO_RequestOSFileHandleReply()); 478 return PP_OK_COMPLETIONPENDING; 479 } 480 481 int32_t PepperFileIOHost::OnHostMsgGetOSFileDescriptor( 482 ppapi::host::HostMessageContext* context) { 483 if (!is_running_in_process_) 484 return PP_ERROR_FAILED; 485 486 int32_t fd = 487 #if defined(OS_POSIX) 488 file_; 489 #elif defined(OS_WIN) 490 reinterpret_cast<uintptr_t>(file_); 491 #else 492 -1; 493 #endif 494 495 host()->SendReply(context->MakeReplyMessageContext(), 496 PpapiPluginMsg_FileIO_GetOSFileDescriptorReply(fd)); 497 return PP_OK_COMPLETIONPENDING; 498 } 499 500 void PepperFileIOHost::ExecutePlatformGeneralCallback( 501 ppapi::host::ReplyMessageContext reply_context, 502 base::PlatformFileError error_code) { 503 reply_context.params.set_result( 504 ppapi::PlatformFileErrorToPepperError(error_code)); 505 host()->SendReply(reply_context, PpapiPluginMsg_FileIO_GeneralReply()); 506 state_manager_.SetOperationFinished(); 507 } 508 509 void PepperFileIOHost::ExecutePlatformOpenFileCallback( 510 ppapi::host::ReplyMessageContext reply_context, 511 base::PlatformFileError error_code, 512 base::PassPlatformFile file) { 513 int32_t pp_error = ppapi::PlatformFileErrorToPepperError(error_code); 514 if (pp_error == PP_OK) 515 state_manager_.SetOpenSucceed(); 516 517 DCHECK(file_ == base::kInvalidPlatformFileValue); 518 file_ = file.ReleaseValue(); 519 520 DCHECK(!quota_file_io_.get()); 521 if (file_ != base::kInvalidPlatformFileValue) { 522 if (file_system_type_ == PP_FILESYSTEMTYPE_LOCALTEMPORARY || 523 file_system_type_ == PP_FILESYSTEMTYPE_LOCALPERSISTENT) { 524 quota_file_io_.reset(new QuotaFileIO( 525 new QuotaFileIODelegate, file_, file_system_url_, file_system_type_)); 526 } 527 528 IPC::PlatformFileForTransit file_for_transit = 529 renderer_ppapi_host_->ShareHandleWithRemote(file_, false); 530 if (!(file_for_transit == IPC::InvalidPlatformFileForTransit())) { 531 // Send the file descriptor to the plugin process. This is used in the 532 // plugin for any file operations that can be done there. 533 // IMPORTANT: Clear PP_FILEOPENFLAG_WRITE and PP_FILEOPENFLAG_APPEND so 534 // the plugin can't write and so bypass our quota checks. 535 int32_t no_write_flags = 536 open_flags_ & ~(PP_FILEOPENFLAG_WRITE | PP_FILEOPENFLAG_APPEND); 537 ppapi::proxy::SerializedHandle file_handle; 538 file_handle.set_file_handle(file_for_transit, no_write_flags); 539 reply_context.params.AppendHandle(file_handle); 540 } 541 } 542 543 reply_context.params.set_result(pp_error); 544 host()->SendReply(reply_context, PpapiPluginMsg_FileIO_OpenReply()); 545 state_manager_.SetOperationFinished(); 546 } 547 548 void PepperFileIOHost::ExecutePlatformOpenFileSystemURLCallback( 549 ppapi::host::ReplyMessageContext reply_context, 550 base::PlatformFileError error_code, 551 base::PassPlatformFile file, 552 quota::QuotaLimitType quota_policy, 553 const PepperFileIOHost::NotifyCloseFileCallback& callback) { 554 if (error_code == base::PLATFORM_FILE_OK) 555 notify_close_file_callback_ = callback; 556 quota_policy_ = quota_policy; 557 ExecutePlatformOpenFileCallback(reply_context, error_code, file); 558 } 559 560 void PepperFileIOHost::ExecutePlatformWriteCallback( 561 ppapi::host::ReplyMessageContext reply_context, 562 base::PlatformFileError error_code, 563 int bytes_written) { 564 // On the plugin side, the callback expects a parameter with different meaning 565 // depends on whether is negative or not. It is the result here. We translate 566 // for the callback. 567 int32_t pp_error = ppapi::PlatformFileErrorToPepperError(error_code); 568 reply_context.params.set_result(ErrorOrByteNumber(pp_error, bytes_written)); 569 host()->SendReply(reply_context, PpapiPluginMsg_FileIO_GeneralReply()); 570 state_manager_.SetOperationFinished(); 571 } 572 573 } // namespace content 574