file_io_resource.cc revision 1320f92c476a1ad9d19dba2a48c72b75566198e9
12a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
22a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
32a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// found in the LICENSE file.
42a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ppapi/proxy/file_io_resource.h"
62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/bind.h"
8ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch#include "base/task_runner_util.h"
92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ipc/ipc_message.h"
102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ppapi/c/pp_errors.h"
112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ppapi/proxy/ppapi_messages.h"
122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ppapi/shared_impl/array_writer.h"
13f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "ppapi/shared_impl/file_ref_create_info.h"
14f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "ppapi/shared_impl/file_system_util.h"
15ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch#include "ppapi/shared_impl/file_type_conversion.h"
162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ppapi/shared_impl/ppapi_globals.h"
17ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch#include "ppapi/shared_impl/proxy_lock.h"
182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ppapi/shared_impl/resource_tracker.h"
192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ppapi/thunk/enter.h"
202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ppapi/thunk/ppb_file_ref_api.h"
215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "ppapi/thunk/ppb_file_system_api.h"
222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)using ppapi::thunk::EnterResourceNoLock;
242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)using ppapi::thunk::PPB_FileIO_API;
252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)using ppapi::thunk::PPB_FileRef_API;
265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)using ppapi::thunk::PPB_FileSystem_API;
272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace {
292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
30ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch// We must allocate a buffer sized according to the request of the plugin. To
315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// reduce the chance of out-of-memory errors, we cap the read and write size to
325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// 32MB. This is OK since the API specifies that it may perform a partial read
335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// or write.
345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)static const int32_t kMaxReadWriteSize = 32 * 1024 * 1024;  // 32MB
35ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// An adapter to let Read() share the same implementation with ReadToArray().
372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void* DummyGetDataBuffer(void* user_data, uint32_t count, uint32_t size) {
382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return user_data;
392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
41ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch// File thread task to close the file handle.
4246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)void DoClose(base::File auto_close_file) {
43ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch}
44ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace
462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace ppapi {
482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace proxy {
492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)FileIOResource::QueryOp::QueryOp(scoped_refptr<FileHolder> file_holder)
5146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    : file_holder_(file_holder) {
521320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  DCHECK(file_holder_.get());
53ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch}
54ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
55ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben MurdochFileIOResource::QueryOp::~QueryOp() {
56ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch}
57ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
58ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdochint32_t FileIOResource::QueryOp::DoWork() {
5946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  return file_holder_->file()->GetInfo(&file_info_) ? PP_OK : PP_ERROR_FAILED;
60ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch}
61ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
6246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)FileIOResource::ReadOp::ReadOp(scoped_refptr<FileHolder> file_holder,
63ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch                               int64_t offset,
64ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch                               int32_t bytes_to_read)
6546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  : file_holder_(file_holder),
66ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    offset_(offset),
67ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    bytes_to_read_(bytes_to_read) {
681320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  DCHECK(file_holder_.get());
69ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch}
70ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
71ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben MurdochFileIOResource::ReadOp::~ReadOp() {
72ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch}
73ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
74ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdochint32_t FileIOResource::ReadOp::DoWork() {
75ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  DCHECK(!buffer_.get());
76ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  buffer_.reset(new char[bytes_to_read_]);
7746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  return file_holder_->file()->Read(offset_, buffer_.get(), bytes_to_read_);
78ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch}
79ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
8046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)FileIOResource::WriteOp::WriteOp(scoped_refptr<FileHolder> file_holder,
815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                 int64_t offset,
82cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                                 scoped_ptr<char[]> buffer,
835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                 int32_t bytes_to_write,
845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                 bool append)
8546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    : file_holder_(file_holder),
86cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      offset_(offset),
87cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      buffer_(buffer.Pass()),
88cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      bytes_to_write_(bytes_to_write),
89cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      append_(append) {
905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)FileIOResource::WriteOp::~WriteOp() {
935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)int32_t FileIOResource::WriteOp::DoWork() {
9646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  // In append mode, we can't call Write, since NaCl doesn't implement fcntl,
9746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  // causing the function to call pwrite, which is incorrect.
985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (append_) {
9946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    return file_holder_->file()->WriteAtCurrentPos(buffer_.get(),
10046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                                                   bytes_to_write_);
1015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  } else {
10246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    return file_holder_->file()->Write(offset_, buffer_.get(), bytes_to_write_);
1035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)FileIOResource::FileIOResource(Connection connection, PP_Instance instance)
107ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    : PluginResource(connection, instance),
1085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      file_system_type_(PP_FILESYSTEMTYPE_INVALID),
1095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      open_flags_(0),
1105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      max_written_offset_(0),
1115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      append_mode_write_amount_(0),
1125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      check_quota_(false),
1135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      called_close_(false) {
1140f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  SendCreate(BROWSER, PpapiHostMsg_FileIO_Create());
1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)FileIOResource::~FileIOResource() {
1185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  Close();
1192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)PPB_FileIO_API* FileIOResource::AsPPB_FileIO_API() {
1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return this;
1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)int32_t FileIOResource::Open(PP_Resource file_ref,
1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                             int32_t open_flags,
1272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                             scoped_refptr<TrackedCallback> callback) {
1285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EnterResourceNoLock<PPB_FileRef_API> enter_file_ref(file_ref, true);
1295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (enter_file_ref.failed())
1302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return PP_ERROR_BADRESOURCE;
1312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  PPB_FileRef_API* file_ref_api = enter_file_ref.object();
133f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  const FileRefCreateInfo& create_info = file_ref_api->GetCreateInfo();
134f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (!FileSystemTypeIsValid(create_info.file_system_type)) {
135ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    NOTREACHED();
136ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    return PP_ERROR_FAILED;
137ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  }
1382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int32_t rv = state_manager_.CheckOperationState(
1392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      FileIOStateManager::OPERATION_EXCLUSIVE, false);
1402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (rv != PP_OK)
1412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return rv;
1422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  open_flags_ = open_flags;
144f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  file_system_type_ = create_info.file_system_type;
1455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (create_info.file_system_plugin_resource) {
1475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    EnterResourceNoLock<PPB_FileSystem_API> enter_file_system(
1485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        create_info.file_system_plugin_resource, true);
1495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (enter_file_system.failed())
1505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return PP_ERROR_FAILED;
1515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // Take a reference on the FileSystem resource. The FileIO host uses the
1525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // FileSystem host for running tasks and checking quota.
1535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    file_system_resource_ = enter_file_system.resource();
1545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
155f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
156d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // Take a reference on the FileRef resource while we're opening the file; we
157d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // don't want the plugin destroying it during the Open operation.
1585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  file_ref_ = enter_file_ref.resource();
159d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
1600f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  Call<PpapiPluginMsg_FileIO_OpenReply>(BROWSER,
1612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      PpapiHostMsg_FileIO_Open(
162d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)          file_ref,
1632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          open_flags),
1642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::Bind(&FileIOResource::OnPluginMsgOpenFileComplete, this,
1652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                 callback));
1662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_EXCLUSIVE);
1682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return PP_OK_COMPLETIONPENDING;
1692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)int32_t FileIOResource::Query(PP_FileInfo* info,
1722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                              scoped_refptr<TrackedCallback> callback) {
1732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int32_t rv = state_manager_.CheckOperationState(
1742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      FileIOStateManager::OPERATION_EXCLUSIVE, true);
1752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (rv != PP_OK)
1762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return rv;
177ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  if (!info)
178ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    return PP_ERROR_BADARGUMENT;
17946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  if (!FileHolder::IsValid(file_holder_))
180ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    return PP_ERROR_FAILED;
1812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_EXCLUSIVE);
183ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
184ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  // If the callback is blocking, perform the task on the calling thread.
185ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  if (callback->is_blocking()) {
1861e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    int32_t result = PP_ERROR_FAILED;
1875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    base::File::Info file_info;
1881e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    // The plugin could release its reference to this instance when we release
1891e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    // the proxy lock below.
1901e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    scoped_refptr<FileIOResource> protect(this);
191ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    {
192ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      // Release the proxy lock while making a potentially slow file call.
193ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      ProxyAutoUnlock unlock;
19446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      if (file_holder_->file()->GetInfo(&file_info))
1951e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)        result = PP_OK;
1961e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    }
1971e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    if (result == PP_OK) {
1981e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      // This writes the file info into the plugin's PP_FileInfo struct.
1995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      ppapi::FileInfoToPepperFileInfo(file_info,
2005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                      file_system_type_,
2015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                      info);
202ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    }
2031e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    state_manager_.SetOperationFinished();
2041e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    return result;
205ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  }
206ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
207ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  // For the non-blocking case, post a task to the file thread and add a
208ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  // completion task to write the result.
20946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  scoped_refptr<QueryOp> query_op(new QueryOp(file_holder_));
210ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  base::PostTaskAndReplyWithResult(
2114e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      PpapiGlobals::Get()->GetFileTaskRunner(),
212ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      FROM_HERE,
213ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      Bind(&FileIOResource::QueryOp::DoWork, query_op),
214ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      RunWhileLocked(Bind(&TrackedCallback::Run, callback)));
215ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  callback->set_completion_task(
216ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      Bind(&FileIOResource::OnQueryComplete, this, query_op, info));
217ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
2182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return PP_OK_COMPLETIONPENDING;
2192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)int32_t FileIOResource::Touch(PP_Time last_access_time,
2222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                              PP_Time last_modified_time,
2232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                              scoped_refptr<TrackedCallback> callback) {
2242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int32_t rv = state_manager_.CheckOperationState(
2252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      FileIOStateManager::OPERATION_EXCLUSIVE, true);
2262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (rv != PP_OK)
2272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return rv;
2282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2290f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  Call<PpapiPluginMsg_FileIO_GeneralReply>(BROWSER,
2302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      PpapiHostMsg_FileIO_Touch(last_access_time, last_modified_time),
2312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::Bind(&FileIOResource::OnPluginMsgGeneralComplete, this,
2322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                 callback));
2332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_EXCLUSIVE);
2352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return PP_OK_COMPLETIONPENDING;
2362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)int32_t FileIOResource::Read(int64_t offset,
2392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                             char* buffer,
2402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                             int32_t bytes_to_read,
2412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                             scoped_refptr<TrackedCallback> callback) {
2422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int32_t rv = state_manager_.CheckOperationState(
2432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      FileIOStateManager::OPERATION_READ, true);
2442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (rv != PP_OK)
2452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return rv;
2462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  PP_ArrayOutput output_adapter;
2482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  output_adapter.GetDataBuffer = &DummyGetDataBuffer;
2492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  output_adapter.user_data = buffer;
2502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return ReadValidated(offset, bytes_to_read, output_adapter, callback);
2512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)int32_t FileIOResource::ReadToArray(int64_t offset,
2542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                    int32_t max_read_length,
2552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                    PP_ArrayOutput* array_output,
2562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                    scoped_refptr<TrackedCallback> callback) {
2572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(array_output);
2582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int32_t rv = state_manager_.CheckOperationState(
2592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      FileIOStateManager::OPERATION_READ, true);
2602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (rv != PP_OK)
2612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return rv;
2622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return ReadValidated(offset, max_read_length, *array_output, callback);
2642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)int32_t FileIOResource::Write(int64_t offset,
2672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                              const char* buffer,
2682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                              int32_t bytes_to_write,
2692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                              scoped_refptr<TrackedCallback> callback) {
2705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!buffer)
2715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return PP_ERROR_FAILED;
2725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (offset < 0 || bytes_to_write < 0)
2735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return PP_ERROR_FAILED;
27446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  if (!FileHolder::IsValid(file_holder_))
2755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return PP_ERROR_FAILED;
2765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int32_t rv = state_manager_.CheckOperationState(
2782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      FileIOStateManager::OPERATION_WRITE, true);
2792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (rv != PP_OK)
2802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return rv;
2812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_WRITE);
2835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (check_quota_) {
2855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    int64_t increase = 0;
2865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    uint64_t max_offset = 0;
2875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    bool append = (open_flags_ & PP_FILEOPENFLAG_APPEND) != 0;
2885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (append) {
2895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      increase = bytes_to_write;
2905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    } else {
2915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      uint64_t max_offset = offset + bytes_to_write;
2925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      if (max_offset > static_cast<uint64_t>(kint64max))
2935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        return PP_ERROR_FAILED;  // amount calculation would overflow.
2945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      increase = static_cast<int64_t>(max_offset) - max_written_offset_;
2955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
2965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (increase > 0) {
298cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      // Request a quota reservation. This makes the Write asynchronous, so we
299cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      // must copy the plugin's buffer.
300cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      scoped_ptr<char[]> copy(new char[bytes_to_write]);
301cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      memcpy(copy.get(), buffer, bytes_to_write);
3025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      int64_t result =
3035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          file_system_resource_->AsPPB_FileSystem_API()->RequestQuota(
3045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)              increase,
3055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)              base::Bind(&FileIOResource::OnRequestWriteQuotaComplete,
3065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                         this,
307cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                         offset,
308cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                         base::Passed(&copy),
309cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                         bytes_to_write,
310cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                         callback));
3115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      if (result == PP_OK_COMPLETIONPENDING)
3125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        return PP_OK_COMPLETIONPENDING;
3135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      DCHECK(result == increase);
3145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      if (append)
3165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        append_mode_write_amount_ += bytes_to_write;
3175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      else
3185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        max_written_offset_ = max_offset;
3195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
3205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
3215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return WriteValidated(offset, buffer, bytes_to_write, callback);
3222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)int32_t FileIOResource::SetLength(int64_t length,
3252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                  scoped_refptr<TrackedCallback> callback) {
3262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int32_t rv = state_manager_.CheckOperationState(
3272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      FileIOStateManager::OPERATION_EXCLUSIVE, true);
3282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (rv != PP_OK)
3292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return rv;
3305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (length < 0)
3315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return PP_ERROR_FAILED;
3322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (check_quota_) {
3345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    int64_t increase = length - max_written_offset_;
3355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (increase > 0) {
3365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      int32_t result =
3375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          file_system_resource_->AsPPB_FileSystem_API()->RequestQuota(
3385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)              increase,
3395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)              base::Bind(&FileIOResource::OnRequestSetLengthQuotaComplete,
3405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                         this,
3415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                         length, callback));
3425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      if (result == PP_OK_COMPLETIONPENDING) {
3435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        state_manager_.SetPendingOperation(
3445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            FileIOStateManager::OPERATION_EXCLUSIVE);
3455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        return PP_OK_COMPLETIONPENDING;
3465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      }
3475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      DCHECK(result == increase);
3485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      max_written_offset_ = length;
3495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
3505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
3512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_EXCLUSIVE);
3535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  SetLengthValidated(length, callback);
3542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return PP_OK_COMPLETIONPENDING;
3552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)int32_t FileIOResource::Flush(scoped_refptr<TrackedCallback> callback) {
3582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int32_t rv = state_manager_.CheckOperationState(
3592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      FileIOStateManager::OPERATION_EXCLUSIVE, true);
3602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (rv != PP_OK)
3612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return rv;
3622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3630f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  Call<PpapiPluginMsg_FileIO_GeneralReply>(BROWSER,
3642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      PpapiHostMsg_FileIO_Flush(),
3652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::Bind(&FileIOResource::OnPluginMsgGeneralComplete, this,
3662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                 callback));
3672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_EXCLUSIVE);
3692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return PP_OK_COMPLETIONPENDING;
3702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)int64_t FileIOResource::GetMaxWrittenOffset() const {
3735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return max_written_offset_;
3745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
3755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)int64_t FileIOResource::GetAppendModeWriteAmount() const {
3775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return append_mode_write_amount_;
3785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
3795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void FileIOResource::SetMaxWrittenOffset(int64_t max_written_offset) {
3815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  max_written_offset_ = max_written_offset;
3825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
3835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void FileIOResource::SetAppendModeWriteAmount(
3855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    int64_t append_mode_write_amount) {
3865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  append_mode_write_amount_ = append_mode_write_amount;
3875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
3885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void FileIOResource::Close() {
3905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (called_close_)
3915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
3925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  called_close_ = true;
3945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (check_quota_) {
3955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    check_quota_ = false;
3965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    file_system_resource_->AsPPB_FileSystem_API()->CloseQuotaFile(
3975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        pp_resource());
3984e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
3995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4001320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (file_holder_.get())
40146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    file_holder_ = NULL;
4025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  Post(BROWSER, PpapiHostMsg_FileIO_Close(
4045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      FileGrowth(max_written_offset_, append_mode_write_amount_)));
4052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
4062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
407ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdochint32_t FileIOResource::RequestOSFileHandle(
408ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    PP_FileHandle* handle,
409ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    scoped_refptr<TrackedCallback> callback) {
410ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  int32_t rv = state_manager_.CheckOperationState(
411ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      FileIOStateManager::OPERATION_EXCLUSIVE, true);
412ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  if (rv != PP_OK)
413ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    return rv;
414ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
4150f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  Call<PpapiPluginMsg_FileIO_RequestOSFileHandleReply>(BROWSER,
416ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      PpapiHostMsg_FileIO_RequestOSFileHandle(),
417ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      base::Bind(&FileIOResource::OnPluginMsgRequestOSFileHandleComplete, this,
418ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch                 callback, handle));
419ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
420ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_EXCLUSIVE);
421ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  return PP_OK_COMPLETIONPENDING;
422ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch}
423ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
42446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)FileIOResource::FileHolder::FileHolder(PP_FileHandle file_handle)
42546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    : file_(file_handle) {
4262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
4272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4284e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// static
42946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)bool FileIOResource::FileHolder::IsValid(
43046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    const scoped_refptr<FileIOResource::FileHolder>& handle) {
4311320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  return handle.get() && handle->file_.IsValid();
4324e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
433ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
43446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)FileIOResource::FileHolder::~FileHolder() {
43546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  if (file_.IsValid()) {
4364e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    base::TaskRunner* file_task_runner =
4374e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        PpapiGlobals::Get()->GetFileTaskRunner();
4384e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    file_task_runner->PostTask(FROM_HERE,
43946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                               base::Bind(&DoClose, Passed(&file_)));
4404e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
4412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
4422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)int32_t FileIOResource::ReadValidated(int64_t offset,
4442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                      int32_t bytes_to_read,
4452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                      const PP_ArrayOutput& array_output,
4462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                      scoped_refptr<TrackedCallback> callback) {
447ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  if (bytes_to_read < 0)
448ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    return PP_ERROR_FAILED;
44946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  if (!FileHolder::IsValid(file_holder_))
450ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    return PP_ERROR_FAILED;
451ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
452ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_READ);
453ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
4545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  bytes_to_read = std::min(bytes_to_read, kMaxReadWriteSize);
455ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  if (callback->is_blocking()) {
4561e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    char* buffer = static_cast<char*>(
4571e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)        array_output.GetDataBuffer(array_output.user_data, bytes_to_read, 1));
4581e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    int32_t result = PP_ERROR_FAILED;
4591e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    // The plugin could release its reference to this instance when we release
4601e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    // the proxy lock below.
4611e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    scoped_refptr<FileIOResource> protect(this);
4621e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    if (buffer) {
463ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      // Release the proxy lock while making a potentially slow file call.
464ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      ProxyAutoUnlock unlock;
46546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      result = file_holder_->file()->Read(offset, buffer, bytes_to_read);
4661e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      if (result < 0)
4671e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)        result = PP_ERROR_FAILED;
468ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    }
4691e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    state_manager_.SetOperationFinished();
4701e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    return result;
471ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  }
472ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
473ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  // For the non-blocking case, post a task to the file thread.
4741e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  scoped_refptr<ReadOp> read_op(
47546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      new ReadOp(file_holder_, offset, bytes_to_read));
476ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  base::PostTaskAndReplyWithResult(
4774e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      PpapiGlobals::Get()->GetFileTaskRunner(),
478ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      FROM_HERE,
479ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      Bind(&FileIOResource::ReadOp::DoWork, read_op),
480ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      RunWhileLocked(Bind(&TrackedCallback::Run, callback)));
481ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  callback->set_completion_task(
482ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      Bind(&FileIOResource::OnReadComplete, this, read_op, array_output));
483ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
4842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return PP_OK_COMPLETIONPENDING;
4852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
4862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)int32_t FileIOResource::WriteValidated(
4885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    int64_t offset,
4895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const char* buffer,
4905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    int32_t bytes_to_write,
4915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    scoped_refptr<TrackedCallback> callback) {
4925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  bool append = (open_flags_ & PP_FILEOPENFLAG_APPEND) != 0;
4935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (callback->is_blocking()) {
4945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    int32_t result;
4955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    {
4965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      // Release the proxy lock while making a potentially slow file call.
4975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      ProxyAutoUnlock unlock;
4985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      if (append) {
49946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)        result = file_holder_->file()->WriteAtCurrentPos(buffer,
50046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                                                         bytes_to_write);
5015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      } else {
50246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)        result = file_holder_->file()->Write(offset, buffer, bytes_to_write);
5035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      }
5045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
5055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (result < 0)
5065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      result = PP_ERROR_FAILED;
5075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
5085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    state_manager_.SetOperationFinished();
5095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return result;
5105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
5115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
512cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // For the non-blocking case, post a task to the file thread. We must copy the
513cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // plugin's buffer at this point.
514cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  scoped_ptr<char[]> copy(new char[bytes_to_write]);
515cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  memcpy(copy.get(), buffer, bytes_to_write);
5165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  scoped_refptr<WriteOp> write_op(
51746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      new WriteOp(file_holder_, offset, copy.Pass(), bytes_to_write, append));
5185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::PostTaskAndReplyWithResult(
5195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      PpapiGlobals::Get()->GetFileTaskRunner(),
5205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      FROM_HERE,
5215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      Bind(&FileIOResource::WriteOp::DoWork, write_op),
5225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      RunWhileLocked(Bind(&TrackedCallback::Run, callback)));
523cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  callback->set_completion_task(Bind(&FileIOResource::OnWriteComplete, this));
5245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
5255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return PP_OK_COMPLETIONPENDING;
5265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
5275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
5285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void FileIOResource::SetLengthValidated(
5295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    int64_t length,
5305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    scoped_refptr<TrackedCallback> callback) {
5315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  Call<PpapiPluginMsg_FileIO_GeneralReply>(BROWSER,
5325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      PpapiHostMsg_FileIO_SetLength(length),
5335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      base::Bind(&FileIOResource::OnPluginMsgGeneralComplete, this,
5345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 callback));
5355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
5365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // On the browser side we grow |max_written_offset_| monotonically, due to the
5375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // unpredictable ordering of plugin side Write and SetLength calls. Match that
5385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // behavior here.
5395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (max_written_offset_ < length)
5405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    max_written_offset_ = length;
5415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
5425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
543ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdochint32_t FileIOResource::OnQueryComplete(scoped_refptr<QueryOp> query_op,
544ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch                                        PP_FileInfo* info,
545ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch                                        int32_t result) {
546ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  DCHECK(state_manager_.get_pending_operation() ==
547ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch         FileIOStateManager::OPERATION_EXCLUSIVE);
548ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
549ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  if (result == PP_OK) {
550ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    // This writes the file info into the plugin's PP_FileInfo struct.
5515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    ppapi::FileInfoToPepperFileInfo(query_op->file_info(),
5525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                    file_system_type_,
5535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                    info);
554ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  }
555ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  state_manager_.SetOperationFinished();
556ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  return result;
557ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch}
558ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
559ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdochint32_t FileIOResource::OnReadComplete(scoped_refptr<ReadOp> read_op,
560ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch                                       PP_ArrayOutput array_output,
561ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch                                       int32_t result) {
562ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  DCHECK(state_manager_.get_pending_operation() ==
563ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch         FileIOStateManager::OPERATION_READ);
564ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  if (result >= 0) {
565ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    ArrayWriter output;
566ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    output.set_pp_array_output(array_output);
567ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    if (output.is_valid())
568ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      output.StoreArray(read_op->buffer(), result);
569ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    else
570ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      result = PP_ERROR_FAILED;
571ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  } else {
572ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    // The read operation failed.
573ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    result = PP_ERROR_FAILED;
574ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  }
575ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  state_manager_.SetOperationFinished();
576ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  return result;
577c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
578c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
5795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void FileIOResource::OnRequestWriteQuotaComplete(
5805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    int64_t offset,
581cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    scoped_ptr<char[]> buffer,
5825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    int32_t bytes_to_write,
5835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    scoped_refptr<TrackedCallback> callback,
5845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    int64_t granted) {
5855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(granted >= 0);
5865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (granted == 0) {
5875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    callback->Run(PP_ERROR_NOQUOTA);
5885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
5895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
5905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (open_flags_ & PP_FILEOPENFLAG_APPEND) {
5915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    DCHECK_LE(bytes_to_write, granted);
5925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    append_mode_write_amount_ += bytes_to_write;
5935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  } else {
5945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    DCHECK_LE(offset + bytes_to_write - max_written_offset_, granted);
5955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
5965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    int64_t max_offset = offset + bytes_to_write;
5975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (max_written_offset_ < max_offset)
5985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      max_written_offset_ = max_offset;
5995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
6005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
601cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (callback->is_blocking()) {
602cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    int32_t result =
603cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        WriteValidated(offset, buffer.get(), bytes_to_write, callback);
604cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    DCHECK(result != PP_OK_COMPLETIONPENDING);
6055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    callback->Run(result);
606cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  } else {
607cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    bool append = (open_flags_ & PP_FILEOPENFLAG_APPEND) != 0;
608cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    scoped_refptr<WriteOp> write_op(new WriteOp(
60946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)        file_holder_, offset, buffer.Pass(), bytes_to_write, append));
610cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    base::PostTaskAndReplyWithResult(
611cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        PpapiGlobals::Get()->GetFileTaskRunner(),
612cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        FROM_HERE,
613cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        Bind(&FileIOResource::WriteOp::DoWork, write_op),
614cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        RunWhileLocked(Bind(&TrackedCallback::Run, callback)));
615cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    callback->set_completion_task(Bind(&FileIOResource::OnWriteComplete, this));
616cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
6175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
6185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
6195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void FileIOResource::OnRequestSetLengthQuotaComplete(
6205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    int64_t length,
6215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    scoped_refptr<TrackedCallback> callback,
6225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    int64_t granted) {
6235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(granted >= 0);
6245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (granted == 0) {
6255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    callback->Run(PP_ERROR_NOQUOTA);
6265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
6275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
6285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
6295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK_LE(length - max_written_offset_, granted);
6305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (max_written_offset_ < length)
6315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    max_written_offset_ = length;
6325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  SetLengthValidated(length, callback);
6335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
6345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
635cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)int32_t FileIOResource::OnWriteComplete(int32_t result) {
6365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(state_manager_.get_pending_operation() ==
6375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)         FileIOStateManager::OPERATION_WRITE);
6385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // |result| is the return value of WritePlatformFile; -1 indicates failure.
6395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (result < 0)
6405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    result = PP_ERROR_FAILED;
6415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
6425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  state_manager_.SetOperationFinished();
6435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return result;
6445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
6455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
6462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void FileIOResource::OnPluginMsgGeneralComplete(
6472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    scoped_refptr<TrackedCallback> callback,
6482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const ResourceMessageReplyParams& params) {
6492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(state_manager_.get_pending_operation() ==
6502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)         FileIOStateManager::OPERATION_EXCLUSIVE ||
6512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)         state_manager_.get_pending_operation() ==
6522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)         FileIOStateManager::OPERATION_WRITE);
653ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  // End this operation now, so the user's callback can execute another FileIO
654ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  // operation, assuming there are no other pending operations.
6552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  state_manager_.SetOperationFinished();
6562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  callback->Run(params.result());
6572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
6582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void FileIOResource::OnPluginMsgOpenFileComplete(
6602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    scoped_refptr<TrackedCallback> callback,
6615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const ResourceMessageReplyParams& params,
6625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    PP_Resource quota_file_system,
6635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    int64_t max_written_offset) {
6642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(state_manager_.get_pending_operation() ==
6652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)         FileIOStateManager::OPERATION_EXCLUSIVE);
666d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
667d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // Release the FileRef resource.
668d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  file_ref_ = NULL;
6695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  int32_t result = params.result();
6705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (result == PP_OK) {
6712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    state_manager_.SetOpenSucceed();
672a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
6735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (quota_file_system) {
6745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      DCHECK(quota_file_system == file_system_resource_->pp_resource());
6755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      check_quota_ = true;
6765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      max_written_offset_ = max_written_offset;
6775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      file_system_resource_->AsPPB_FileSystem_API()->OpenQuotaFile(
6785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          pp_resource());
6795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
6805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
6815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    IPC::PlatformFileForTransit transit_file;
6825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (params.TakeFileHandleAtIndex(0, &transit_file)) {
68346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      file_holder_ = new FileHolder(
6845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          IPC::PlatformFileForTransitToPlatformFile(transit_file));
6855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
6864e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
687ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  // End this operation now, so the user's callback can execute another FileIO
688ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  // operation, assuming there are no other pending operations.
6892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  state_manager_.SetOperationFinished();
690a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  callback->Run(result);
6912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
6922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
693c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void FileIOResource::OnPluginMsgRequestOSFileHandleComplete(
694c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    scoped_refptr<TrackedCallback> callback,
695c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    PP_FileHandle* output_handle,
696c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const ResourceMessageReplyParams& params) {
697c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(state_manager_.get_pending_operation() ==
698c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)         FileIOStateManager::OPERATION_EXCLUSIVE);
699c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
700c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!TrackedCallback::IsPending(callback)) {
701c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    state_manager_.SetOperationFinished();
702c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return;
703c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
704c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
705c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  int32_t result = params.result();
706c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  IPC::PlatformFileForTransit transit_file;
707c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!params.TakeFileHandleAtIndex(0, &transit_file))
708c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    result = PP_ERROR_FAILED;
709c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  *output_handle = IPC::PlatformFileForTransitToPlatformFile(transit_file);
710c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
711ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  // End this operation now, so the user's callback can execute another FileIO
712ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  // operation, assuming there are no other pending operations.
713c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  state_manager_.SetOperationFinished();
714c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  callback->Run(result);
715c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
716c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
7172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace proxy
7182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace ppapi
719