Home | History | Annotate | Download | only in pepper
      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(&notify_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