root/ppapi/proxy/file_io_resource.cc

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. DummyGetDataBuffer
  2. DoClose
  3. DoWork
  4. bytes_to_read_
  5. DoWork
  6. append_
  7. DoWork
  8. called_close_
  9. AsPPB_FileIO_API
  10. Open
  11. Query
  12. Touch
  13. Read
  14. ReadToArray
  15. Write
  16. SetLength
  17. Flush
  18. GetMaxWrittenOffset
  19. GetAppendModeWriteAmount
  20. SetMaxWrittenOffset
  21. SetAppendModeWriteAmount
  22. Close
  23. RequestOSFileHandle
  24. IsValid
  25. ReadValidated
  26. WriteValidated
  27. SetLengthValidated
  28. OnQueryComplete
  29. OnReadComplete
  30. OnRequestWriteQuotaComplete
  31. OnRequestSetLengthQuotaComplete
  32. OnWriteComplete
  33. OnPluginMsgGeneralComplete
  34. OnPluginMsgOpenFileComplete
  35. OnPluginMsgRequestOSFileHandleComplete

// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "ppapi/proxy/file_io_resource.h"

#include "base/bind.h"
#include "base/task_runner_util.h"
#include "ipc/ipc_message.h"
#include "ppapi/c/pp_errors.h"
#include "ppapi/proxy/ppapi_messages.h"
#include "ppapi/shared_impl/array_writer.h"
#include "ppapi/shared_impl/file_ref_create_info.h"
#include "ppapi/shared_impl/file_system_util.h"
#include "ppapi/shared_impl/file_type_conversion.h"
#include "ppapi/shared_impl/ppapi_globals.h"
#include "ppapi/shared_impl/proxy_lock.h"
#include "ppapi/shared_impl/resource_tracker.h"
#include "ppapi/thunk/enter.h"
#include "ppapi/thunk/ppb_file_ref_api.h"
#include "ppapi/thunk/ppb_file_system_api.h"

using ppapi::thunk::EnterResourceNoLock;
using ppapi::thunk::PPB_FileIO_API;
using ppapi::thunk::PPB_FileRef_API;
using ppapi::thunk::PPB_FileSystem_API;

namespace {

// We must allocate a buffer sized according to the request of the plugin. To
// reduce the chance of out-of-memory errors, we cap the read and write size to
// 32MB. This is OK since the API specifies that it may perform a partial read
// or write.
static const int32_t kMaxReadWriteSize = 32 * 1024 * 1024;  // 32MB

// An adapter to let Read() share the same implementation with ReadToArray().
void* DummyGetDataBuffer(void* user_data, uint32_t count, uint32_t size) {
  return user_data;
}

// File thread task to close the file handle.
void DoClose(base::PlatformFile file) {
  base::ClosePlatformFile(file);
}

}  // namespace

namespace ppapi {
namespace proxy {

FileIOResource::QueryOp::QueryOp(scoped_refptr<FileHandleHolder> file_handle)
    : file_handle_(file_handle) {
  DCHECK(file_handle_);
}

FileIOResource::QueryOp::~QueryOp() {
}

int32_t FileIOResource::QueryOp::DoWork() {
  // TODO(rvargas): Convert this code to use base::File.
  base::File file(file_handle_->raw_handle());
  bool success = file.GetInfo(&file_info_);
  file.TakePlatformFile();
  return success ? PP_OK : PP_ERROR_FAILED;
}

FileIOResource::ReadOp::ReadOp(scoped_refptr<FileHandleHolder> file_handle,
                               int64_t offset,
                               int32_t bytes_to_read)
  : file_handle_(file_handle),
    offset_(offset),
    bytes_to_read_(bytes_to_read) {
  DCHECK(file_handle_);
}

FileIOResource::ReadOp::~ReadOp() {
}

int32_t FileIOResource::ReadOp::DoWork() {
  DCHECK(!buffer_.get());
  buffer_.reset(new char[bytes_to_read_]);
  return base::ReadPlatformFile(
      file_handle_->raw_handle(), offset_, buffer_.get(), bytes_to_read_);
}

FileIOResource::WriteOp::WriteOp(scoped_refptr<FileHandleHolder> file_handle,
                                 int64_t offset,
                                 const char* buffer,
                                 int32_t bytes_to_write,
                                 bool append)
  : file_handle_(file_handle),
    offset_(offset),
    buffer_(buffer),
    bytes_to_write_(bytes_to_write),
    append_(append) {
}

FileIOResource::WriteOp::~WriteOp() {
}

int32_t FileIOResource::WriteOp::DoWork() {
  // We can't just call WritePlatformFile in append mode, since NaCl doesn't
  // implement fcntl, causing the function to call pwrite, which is incorrect.
  if (append_) {
    return base::WritePlatformFileAtCurrentPos(
        file_handle_->raw_handle(), buffer_, bytes_to_write_);
  } else {
    return base::WritePlatformFile(
        file_handle_->raw_handle(), offset_, buffer_, bytes_to_write_);
  }
}

FileIOResource::FileIOResource(Connection connection, PP_Instance instance)
    : PluginResource(connection, instance),
      file_system_type_(PP_FILESYSTEMTYPE_INVALID),
      open_flags_(0),
      max_written_offset_(0),
      append_mode_write_amount_(0),
      check_quota_(false),
      called_close_(false) {
  SendCreate(BROWSER, PpapiHostMsg_FileIO_Create());
}

FileIOResource::~FileIOResource() {
  Close();
}

PPB_FileIO_API* FileIOResource::AsPPB_FileIO_API() {
  return this;
}

int32_t FileIOResource::Open(PP_Resource file_ref,
                             int32_t open_flags,
                             scoped_refptr<TrackedCallback> callback) {
  EnterResourceNoLock<PPB_FileRef_API> enter_file_ref(file_ref, true);
  if (enter_file_ref.failed())
    return PP_ERROR_BADRESOURCE;

  PPB_FileRef_API* file_ref_api = enter_file_ref.object();
  const FileRefCreateInfo& create_info = file_ref_api->GetCreateInfo();
  if (!FileSystemTypeIsValid(create_info.file_system_type)) {
    NOTREACHED();
    return PP_ERROR_FAILED;
  }
  int32_t rv = state_manager_.CheckOperationState(
      FileIOStateManager::OPERATION_EXCLUSIVE, false);
  if (rv != PP_OK)
    return rv;

  open_flags_ = open_flags;
  file_system_type_ = create_info.file_system_type;

  if (create_info.file_system_plugin_resource) {
    EnterResourceNoLock<PPB_FileSystem_API> enter_file_system(
        create_info.file_system_plugin_resource, true);
    if (enter_file_system.failed())
      return PP_ERROR_FAILED;
    // Take a reference on the FileSystem resource. The FileIO host uses the
    // FileSystem host for running tasks and checking quota.
    file_system_resource_ = enter_file_system.resource();
  }

  // Take a reference on the FileRef resource while we're opening the file; we
  // don't want the plugin destroying it during the Open operation.
  file_ref_ = enter_file_ref.resource();

  Call<PpapiPluginMsg_FileIO_OpenReply>(BROWSER,
      PpapiHostMsg_FileIO_Open(
          file_ref,
          open_flags),
      base::Bind(&FileIOResource::OnPluginMsgOpenFileComplete, this,
                 callback));

  state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_EXCLUSIVE);
  return PP_OK_COMPLETIONPENDING;
}

int32_t FileIOResource::Query(PP_FileInfo* info,
                              scoped_refptr<TrackedCallback> callback) {
  int32_t rv = state_manager_.CheckOperationState(
      FileIOStateManager::OPERATION_EXCLUSIVE, true);
  if (rv != PP_OK)
    return rv;
  if (!info)
    return PP_ERROR_BADARGUMENT;
  if (!FileHandleHolder::IsValid(file_handle_))
    return PP_ERROR_FAILED;

  state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_EXCLUSIVE);

  // If the callback is blocking, perform the task on the calling thread.
  if (callback->is_blocking()) {
    int32_t result = PP_ERROR_FAILED;
    base::File::Info file_info;
    // The plugin could release its reference to this instance when we release
    // the proxy lock below.
    scoped_refptr<FileIOResource> protect(this);
    {
      // Release the proxy lock while making a potentially slow file call.
      ProxyAutoUnlock unlock;
      // TODO(rvargas): Convert this code to base::File.
      base::File file(file_handle_->raw_handle());
      bool success = file.GetInfo(&file_info);
      file.TakePlatformFile();
      if (success)
        result = PP_OK;
    }
    if (result == PP_OK) {
      // This writes the file info into the plugin's PP_FileInfo struct.
      ppapi::FileInfoToPepperFileInfo(file_info,
                                      file_system_type_,
                                      info);
    }
    state_manager_.SetOperationFinished();
    return result;
  }

  // For the non-blocking case, post a task to the file thread and add a
  // completion task to write the result.
  scoped_refptr<QueryOp> query_op(new QueryOp(file_handle_));
  base::PostTaskAndReplyWithResult(
      PpapiGlobals::Get()->GetFileTaskRunner(),
      FROM_HERE,
      Bind(&FileIOResource::QueryOp::DoWork, query_op),
      RunWhileLocked(Bind(&TrackedCallback::Run, callback)));
  callback->set_completion_task(
      Bind(&FileIOResource::OnQueryComplete, this, query_op, info));

  return PP_OK_COMPLETIONPENDING;
}

int32_t FileIOResource::Touch(PP_Time last_access_time,
                              PP_Time last_modified_time,
                              scoped_refptr<TrackedCallback> callback) {
  int32_t rv = state_manager_.CheckOperationState(
      FileIOStateManager::OPERATION_EXCLUSIVE, true);
  if (rv != PP_OK)
    return rv;

  Call<PpapiPluginMsg_FileIO_GeneralReply>(BROWSER,
      PpapiHostMsg_FileIO_Touch(last_access_time, last_modified_time),
      base::Bind(&FileIOResource::OnPluginMsgGeneralComplete, this,
                 callback));

  state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_EXCLUSIVE);
  return PP_OK_COMPLETIONPENDING;
}

int32_t FileIOResource::Read(int64_t offset,
                             char* buffer,
                             int32_t bytes_to_read,
                             scoped_refptr<TrackedCallback> callback) {
  int32_t rv = state_manager_.CheckOperationState(
      FileIOStateManager::OPERATION_READ, true);
  if (rv != PP_OK)
    return rv;

  PP_ArrayOutput output_adapter;
  output_adapter.GetDataBuffer = &DummyGetDataBuffer;
  output_adapter.user_data = buffer;
  return ReadValidated(offset, bytes_to_read, output_adapter, callback);
}

int32_t FileIOResource::ReadToArray(int64_t offset,
                                    int32_t max_read_length,
                                    PP_ArrayOutput* array_output,
                                    scoped_refptr<TrackedCallback> callback) {
  DCHECK(array_output);
  int32_t rv = state_manager_.CheckOperationState(
      FileIOStateManager::OPERATION_READ, true);
  if (rv != PP_OK)
    return rv;

  return ReadValidated(offset, max_read_length, *array_output, callback);
}

int32_t FileIOResource::Write(int64_t offset,
                              const char* buffer,
                              int32_t bytes_to_write,
                              scoped_refptr<TrackedCallback> callback) {
  if (!buffer)
    return PP_ERROR_FAILED;
  if (offset < 0 || bytes_to_write < 0)
    return PP_ERROR_FAILED;
  if (!FileHandleHolder::IsValid(file_handle_))
    return PP_ERROR_FAILED;

  int32_t rv = state_manager_.CheckOperationState(
      FileIOStateManager::OPERATION_WRITE, true);
  if (rv != PP_OK)
    return rv;

  state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_WRITE);

  if (check_quota_) {
    int64_t increase = 0;
    uint64_t max_offset = 0;
    bool append = (open_flags_ & PP_FILEOPENFLAG_APPEND) != 0;
    if (append) {
      increase = bytes_to_write;
    } else {
      uint64_t max_offset = offset + bytes_to_write;
      if (max_offset > static_cast<uint64_t>(kint64max))
        return PP_ERROR_FAILED;  // amount calculation would overflow.
      increase = static_cast<int64_t>(max_offset) - max_written_offset_;
    }

    if (increase > 0) {
      int64_t result =
          file_system_resource_->AsPPB_FileSystem_API()->RequestQuota(
              increase,
              base::Bind(&FileIOResource::OnRequestWriteQuotaComplete,
                         this,
                         offset, buffer, bytes_to_write, callback));
      if (result == PP_OK_COMPLETIONPENDING)
        return PP_OK_COMPLETIONPENDING;
      DCHECK(result == increase);

      if (append)
        append_mode_write_amount_ += bytes_to_write;
      else
        max_written_offset_ = max_offset;
    }
  }
  return WriteValidated(offset, buffer, bytes_to_write, callback);
}

int32_t FileIOResource::SetLength(int64_t length,
                                  scoped_refptr<TrackedCallback> callback) {
  int32_t rv = state_manager_.CheckOperationState(
      FileIOStateManager::OPERATION_EXCLUSIVE, true);
  if (rv != PP_OK)
    return rv;
  if (length < 0)
    return PP_ERROR_FAILED;

  if (check_quota_) {
    int64_t increase = length - max_written_offset_;
    if (increase > 0) {
      int32_t result =
          file_system_resource_->AsPPB_FileSystem_API()->RequestQuota(
              increase,
              base::Bind(&FileIOResource::OnRequestSetLengthQuotaComplete,
                         this,
                         length, callback));
      if (result == PP_OK_COMPLETIONPENDING) {
        state_manager_.SetPendingOperation(
            FileIOStateManager::OPERATION_EXCLUSIVE);
        return PP_OK_COMPLETIONPENDING;
      }
      DCHECK(result == increase);
      max_written_offset_ = length;
    }
  }

  state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_EXCLUSIVE);
  SetLengthValidated(length, callback);
  return PP_OK_COMPLETIONPENDING;
}

int32_t FileIOResource::Flush(scoped_refptr<TrackedCallback> callback) {
  int32_t rv = state_manager_.CheckOperationState(
      FileIOStateManager::OPERATION_EXCLUSIVE, true);
  if (rv != PP_OK)
    return rv;

  Call<PpapiPluginMsg_FileIO_GeneralReply>(BROWSER,
      PpapiHostMsg_FileIO_Flush(),
      base::Bind(&FileIOResource::OnPluginMsgGeneralComplete, this,
                 callback));

  state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_EXCLUSIVE);
  return PP_OK_COMPLETIONPENDING;
}

int64_t FileIOResource::GetMaxWrittenOffset() const {
  return max_written_offset_;
}

int64_t FileIOResource::GetAppendModeWriteAmount() const {
  return append_mode_write_amount_;
}

void FileIOResource::SetMaxWrittenOffset(int64_t max_written_offset) {
  max_written_offset_ = max_written_offset;
}

void FileIOResource::SetAppendModeWriteAmount(
    int64_t append_mode_write_amount) {
  append_mode_write_amount_ = append_mode_write_amount;
}

void FileIOResource::Close() {
  if (called_close_)
    return;

  called_close_ = true;
  if (check_quota_) {
    check_quota_ = false;
    file_system_resource_->AsPPB_FileSystem_API()->CloseQuotaFile(
        pp_resource());
  }

  if (file_handle_)
    file_handle_ = NULL;

  Post(BROWSER, PpapiHostMsg_FileIO_Close(
      FileGrowth(max_written_offset_, append_mode_write_amount_)));
}

int32_t FileIOResource::RequestOSFileHandle(
    PP_FileHandle* handle,
    scoped_refptr<TrackedCallback> callback) {
  int32_t rv = state_manager_.CheckOperationState(
      FileIOStateManager::OPERATION_EXCLUSIVE, true);
  if (rv != PP_OK)
    return rv;

  Call<PpapiPluginMsg_FileIO_RequestOSFileHandleReply>(BROWSER,
      PpapiHostMsg_FileIO_RequestOSFileHandle(),
      base::Bind(&FileIOResource::OnPluginMsgRequestOSFileHandleComplete, this,
                 callback, handle));

  state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_EXCLUSIVE);
  return PP_OK_COMPLETIONPENDING;
}

FileIOResource::FileHandleHolder::FileHandleHolder(PP_FileHandle file_handle)
    : raw_handle_(file_handle) {
}

// static
bool FileIOResource::FileHandleHolder::IsValid(
    const scoped_refptr<FileIOResource::FileHandleHolder>& handle) {
  return handle && (handle->raw_handle() != base::kInvalidPlatformFileValue);
}

FileIOResource::FileHandleHolder::~FileHandleHolder() {
  if (raw_handle_ != base::kInvalidPlatformFileValue) {
    base::TaskRunner* file_task_runner =
        PpapiGlobals::Get()->GetFileTaskRunner();
    file_task_runner->PostTask(FROM_HERE,
                               base::Bind(&DoClose, raw_handle_));
  }
}

int32_t FileIOResource::ReadValidated(int64_t offset,
                                      int32_t bytes_to_read,
                                      const PP_ArrayOutput& array_output,
                                      scoped_refptr<TrackedCallback> callback) {
  if (bytes_to_read < 0)
    return PP_ERROR_FAILED;
  if (!FileHandleHolder::IsValid(file_handle_))
    return PP_ERROR_FAILED;

  state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_READ);

  bytes_to_read = std::min(bytes_to_read, kMaxReadWriteSize);
  if (callback->is_blocking()) {
    char* buffer = static_cast<char*>(
        array_output.GetDataBuffer(array_output.user_data, bytes_to_read, 1));
    int32_t result = PP_ERROR_FAILED;
    // The plugin could release its reference to this instance when we release
    // the proxy lock below.
    scoped_refptr<FileIOResource> protect(this);
    if (buffer) {
      // Release the proxy lock while making a potentially slow file call.
      ProxyAutoUnlock unlock;
      result = base::ReadPlatformFile(
          file_handle_->raw_handle(), offset, buffer, bytes_to_read);
      if (result < 0)
        result = PP_ERROR_FAILED;
    }
    state_manager_.SetOperationFinished();
    return result;
  }

  // For the non-blocking case, post a task to the file thread.
  scoped_refptr<ReadOp> read_op(
      new ReadOp(file_handle_, offset, bytes_to_read));
  base::PostTaskAndReplyWithResult(
      PpapiGlobals::Get()->GetFileTaskRunner(),
      FROM_HERE,
      Bind(&FileIOResource::ReadOp::DoWork, read_op),
      RunWhileLocked(Bind(&TrackedCallback::Run, callback)));
  callback->set_completion_task(
      Bind(&FileIOResource::OnReadComplete, this, read_op, array_output));

  return PP_OK_COMPLETIONPENDING;
}

int32_t FileIOResource::WriteValidated(
    int64_t offset,
    const char* buffer,
    int32_t bytes_to_write,
    scoped_refptr<TrackedCallback> callback) {
  bool append = (open_flags_ & PP_FILEOPENFLAG_APPEND) != 0;
  if (callback->is_blocking()) {
    int32_t result;
    {
      // Release the proxy lock while making a potentially slow file call.
      ProxyAutoUnlock unlock;
      if (append) {
        result = base::WritePlatformFileAtCurrentPos(
            file_handle_->raw_handle(), buffer, bytes_to_write);
      } else {
        result = base::WritePlatformFile(
            file_handle_->raw_handle(), offset, buffer, bytes_to_write);
      }
    }
    if (result < 0)
      result = PP_ERROR_FAILED;

    state_manager_.SetOperationFinished();
    return result;
  }

  // For the non-blocking case, post a task to the file thread.
  scoped_refptr<WriteOp> write_op(
      new WriteOp(file_handle_, offset, buffer, bytes_to_write, append));
  base::PostTaskAndReplyWithResult(
      PpapiGlobals::Get()->GetFileTaskRunner(),
      FROM_HERE,
      Bind(&FileIOResource::WriteOp::DoWork, write_op),
      RunWhileLocked(Bind(&TrackedCallback::Run, callback)));
  callback->set_completion_task(
      Bind(&FileIOResource::OnWriteComplete, this, write_op));

  return PP_OK_COMPLETIONPENDING;
}

void FileIOResource::SetLengthValidated(
    int64_t length,
    scoped_refptr<TrackedCallback> callback) {
  Call<PpapiPluginMsg_FileIO_GeneralReply>(BROWSER,
      PpapiHostMsg_FileIO_SetLength(length),
      base::Bind(&FileIOResource::OnPluginMsgGeneralComplete, this,
                 callback));

  // On the browser side we grow |max_written_offset_| monotonically, due to the
  // unpredictable ordering of plugin side Write and SetLength calls. Match that
  // behavior here.
  if (max_written_offset_ < length)
    max_written_offset_ = length;
}

int32_t FileIOResource::OnQueryComplete(scoped_refptr<QueryOp> query_op,
                                        PP_FileInfo* info,
                                        int32_t result) {
  DCHECK(state_manager_.get_pending_operation() ==
         FileIOStateManager::OPERATION_EXCLUSIVE);

  if (result == PP_OK) {
    // This writes the file info into the plugin's PP_FileInfo struct.
    ppapi::FileInfoToPepperFileInfo(query_op->file_info(),
                                    file_system_type_,
                                    info);
  }
  state_manager_.SetOperationFinished();
  return result;
}

int32_t FileIOResource::OnReadComplete(scoped_refptr<ReadOp> read_op,
                                       PP_ArrayOutput array_output,
                                       int32_t result) {
  DCHECK(state_manager_.get_pending_operation() ==
         FileIOStateManager::OPERATION_READ);
  if (result >= 0) {
    ArrayWriter output;
    output.set_pp_array_output(array_output);
    if (output.is_valid())
      output.StoreArray(read_op->buffer(), result);
    else
      result = PP_ERROR_FAILED;
  } else {
    // The read operation failed.
    result = PP_ERROR_FAILED;
  }
  state_manager_.SetOperationFinished();
  return result;
}

void FileIOResource::OnRequestWriteQuotaComplete(
    int64_t offset,
    const char* buffer,
    int32_t bytes_to_write,
    scoped_refptr<TrackedCallback> callback,
    int64_t granted) {
  DCHECK(granted >= 0);
  if (granted == 0) {
    callback->Run(PP_ERROR_NOQUOTA);
    return;
  }
  if (open_flags_ & PP_FILEOPENFLAG_APPEND) {
    DCHECK_LE(bytes_to_write, granted);
    append_mode_write_amount_ += bytes_to_write;
  } else {
    DCHECK_LE(offset + bytes_to_write - max_written_offset_, granted);

    int64_t max_offset = offset + bytes_to_write;
    if (max_written_offset_ < max_offset)
      max_written_offset_ = max_offset;
  }

  int32_t result = WriteValidated(offset, buffer, bytes_to_write, callback);
  if (result != PP_OK_COMPLETIONPENDING)
    callback->Run(result);
}

void FileIOResource::OnRequestSetLengthQuotaComplete(
    int64_t length,
    scoped_refptr<TrackedCallback> callback,
    int64_t granted) {
  DCHECK(granted >= 0);
  if (granted == 0) {
    callback->Run(PP_ERROR_NOQUOTA);
    return;
  }

  DCHECK_LE(length - max_written_offset_, granted);
  if (max_written_offset_ < length)
    max_written_offset_ = length;
  SetLengthValidated(length, callback);
}

int32_t FileIOResource::OnWriteComplete(scoped_refptr<WriteOp> write_op,
                                        int32_t result) {
  DCHECK(state_manager_.get_pending_operation() ==
         FileIOStateManager::OPERATION_WRITE);
  // |result| is the return value of WritePlatformFile; -1 indicates failure.
  if (result < 0)
    result = PP_ERROR_FAILED;

  state_manager_.SetOperationFinished();
  return result;
}

void FileIOResource::OnPluginMsgGeneralComplete(
    scoped_refptr<TrackedCallback> callback,
    const ResourceMessageReplyParams& params) {
  DCHECK(state_manager_.get_pending_operation() ==
         FileIOStateManager::OPERATION_EXCLUSIVE ||
         state_manager_.get_pending_operation() ==
         FileIOStateManager::OPERATION_WRITE);
  // End this operation now, so the user's callback can execute another FileIO
  // operation, assuming there are no other pending operations.
  state_manager_.SetOperationFinished();
  callback->Run(params.result());
}

void FileIOResource::OnPluginMsgOpenFileComplete(
    scoped_refptr<TrackedCallback> callback,
    const ResourceMessageReplyParams& params,
    PP_Resource quota_file_system,
    int64_t max_written_offset) {
  DCHECK(state_manager_.get_pending_operation() ==
         FileIOStateManager::OPERATION_EXCLUSIVE);

  // Release the FileRef resource.
  file_ref_ = NULL;
  int32_t result = params.result();
  if (result == PP_OK) {
    state_manager_.SetOpenSucceed();

    if (quota_file_system) {
      DCHECK(quota_file_system == file_system_resource_->pp_resource());
      check_quota_ = true;
      max_written_offset_ = max_written_offset;
      file_system_resource_->AsPPB_FileSystem_API()->OpenQuotaFile(
          pp_resource());
    }

    IPC::PlatformFileForTransit transit_file;
    if (params.TakeFileHandleAtIndex(0, &transit_file)) {
      file_handle_ = new FileHandleHolder(
          IPC::PlatformFileForTransitToPlatformFile(transit_file));
    }
  }
  // End this operation now, so the user's callback can execute another FileIO
  // operation, assuming there are no other pending operations.
  state_manager_.SetOperationFinished();
  callback->Run(result);
}

void FileIOResource::OnPluginMsgRequestOSFileHandleComplete(
    scoped_refptr<TrackedCallback> callback,
    PP_FileHandle* output_handle,
    const ResourceMessageReplyParams& params) {
  DCHECK(state_manager_.get_pending_operation() ==
         FileIOStateManager::OPERATION_EXCLUSIVE);

  if (!TrackedCallback::IsPending(callback)) {
    state_manager_.SetOperationFinished();
    return;
  }

  int32_t result = params.result();
  IPC::PlatformFileForTransit transit_file;
  if (!params.TakeFileHandleAtIndex(0, &transit_file))
    result = PP_ERROR_FAILED;
  *output_handle = IPC::PlatformFileForTransitToPlatformFile(transit_file);

  // End this operation now, so the user's callback can execute another FileIO
  // operation, assuming there are no other pending operations.
  state_manager_.SetOperationFinished();
  callback->Run(result);
}

}  // namespace proxy
}  // namespace ppapi

/* [<][>][^][v][top][bottom][index][help] */