file_io_resource.cc revision 5d1f7b1de12d16ceb2c938c56701a3e8bfa558f7
1// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "ppapi/proxy/file_io_resource.h"
6
7#include "base/bind.h"
8#include "base/task_runner_util.h"
9#include "ipc/ipc_message.h"
10#include "ppapi/c/pp_errors.h"
11#include "ppapi/proxy/ppapi_messages.h"
12#include "ppapi/shared_impl/array_writer.h"
13#include "ppapi/shared_impl/file_ref_create_info.h"
14#include "ppapi/shared_impl/file_system_util.h"
15#include "ppapi/shared_impl/file_type_conversion.h"
16#include "ppapi/shared_impl/ppapi_globals.h"
17#include "ppapi/shared_impl/proxy_lock.h"
18#include "ppapi/shared_impl/resource_tracker.h"
19#include "ppapi/thunk/enter.h"
20#include "ppapi/thunk/ppb_file_ref_api.h"
21#include "ppapi/thunk/ppb_file_system_api.h"
22
23using ppapi::thunk::EnterResourceNoLock;
24using ppapi::thunk::PPB_FileIO_API;
25using ppapi::thunk::PPB_FileRef_API;
26using ppapi::thunk::PPB_FileSystem_API;
27
28namespace {
29
30// We must allocate a buffer sized according to the request of the plugin. To
31// reduce the chance of out-of-memory errors, we cap the read and write size to
32// 32MB. This is OK since the API specifies that it may perform a partial read
33// or write.
34static const int32_t kMaxReadWriteSize = 32 * 1024 * 1024;  // 32MB
35
36// An adapter to let Read() share the same implementation with ReadToArray().
37void* DummyGetDataBuffer(void* user_data, uint32_t count, uint32_t size) {
38  return user_data;
39}
40
41// File thread task to close the file handle.
42void DoClose(base::PlatformFile file) {
43  base::ClosePlatformFile(file);
44}
45
46}  // namespace
47
48namespace ppapi {
49namespace proxy {
50
51FileIOResource::QueryOp::QueryOp(scoped_refptr<FileHandleHolder> file_handle)
52    : file_handle_(file_handle) {
53  DCHECK(file_handle_);
54}
55
56FileIOResource::QueryOp::~QueryOp() {
57}
58
59int32_t FileIOResource::QueryOp::DoWork() {
60  // TODO(rvargas): Convert this code to use base::File.
61  base::File file(file_handle_->raw_handle());
62  bool success = file.GetInfo(&file_info_);
63  file.TakePlatformFile();
64  return success ? PP_OK : PP_ERROR_FAILED;
65}
66
67FileIOResource::ReadOp::ReadOp(scoped_refptr<FileHandleHolder> file_handle,
68                               int64_t offset,
69                               int32_t bytes_to_read)
70  : file_handle_(file_handle),
71    offset_(offset),
72    bytes_to_read_(bytes_to_read) {
73  DCHECK(file_handle_);
74}
75
76FileIOResource::ReadOp::~ReadOp() {
77}
78
79int32_t FileIOResource::ReadOp::DoWork() {
80  DCHECK(!buffer_.get());
81  buffer_.reset(new char[bytes_to_read_]);
82  return base::ReadPlatformFile(
83      file_handle_->raw_handle(), offset_, buffer_.get(), bytes_to_read_);
84}
85
86FileIOResource::WriteOp::WriteOp(scoped_refptr<FileHandleHolder> file_handle,
87                                 int64_t offset,
88                                 const char* buffer,
89                                 int32_t bytes_to_write,
90                                 bool append)
91  : file_handle_(file_handle),
92    offset_(offset),
93    buffer_(buffer),
94    bytes_to_write_(bytes_to_write),
95    append_(append) {
96}
97
98FileIOResource::WriteOp::~WriteOp() {
99}
100
101int32_t FileIOResource::WriteOp::DoWork() {
102  // We can't just call WritePlatformFile in append mode, since NaCl doesn't
103  // implement fcntl, causing the function to call pwrite, which is incorrect.
104  if (append_) {
105    return base::WritePlatformFileAtCurrentPos(
106        file_handle_->raw_handle(), buffer_, bytes_to_write_);
107  } else {
108    return base::WritePlatformFile(
109        file_handle_->raw_handle(), offset_, buffer_, bytes_to_write_);
110  }
111}
112
113FileIOResource::FileIOResource(Connection connection, PP_Instance instance)
114    : PluginResource(connection, instance),
115      file_system_type_(PP_FILESYSTEMTYPE_INVALID),
116      open_flags_(0),
117      max_written_offset_(0),
118      append_mode_write_amount_(0),
119      check_quota_(false),
120      called_close_(false) {
121  SendCreate(BROWSER, PpapiHostMsg_FileIO_Create());
122}
123
124FileIOResource::~FileIOResource() {
125  Close();
126}
127
128PPB_FileIO_API* FileIOResource::AsPPB_FileIO_API() {
129  return this;
130}
131
132int32_t FileIOResource::Open(PP_Resource file_ref,
133                             int32_t open_flags,
134                             scoped_refptr<TrackedCallback> callback) {
135  EnterResourceNoLock<PPB_FileRef_API> enter_file_ref(file_ref, true);
136  if (enter_file_ref.failed())
137    return PP_ERROR_BADRESOURCE;
138
139  PPB_FileRef_API* file_ref_api = enter_file_ref.object();
140  const FileRefCreateInfo& create_info = file_ref_api->GetCreateInfo();
141  if (!FileSystemTypeIsValid(create_info.file_system_type)) {
142    NOTREACHED();
143    return PP_ERROR_FAILED;
144  }
145  int32_t rv = state_manager_.CheckOperationState(
146      FileIOStateManager::OPERATION_EXCLUSIVE, false);
147  if (rv != PP_OK)
148    return rv;
149
150  open_flags_ = open_flags;
151  file_system_type_ = create_info.file_system_type;
152
153  if (create_info.file_system_plugin_resource) {
154    EnterResourceNoLock<PPB_FileSystem_API> enter_file_system(
155        create_info.file_system_plugin_resource, true);
156    if (enter_file_system.failed())
157      return PP_ERROR_FAILED;
158    // Take a reference on the FileSystem resource. The FileIO host uses the
159    // FileSystem host for running tasks and checking quota.
160    file_system_resource_ = enter_file_system.resource();
161  }
162
163  // Take a reference on the FileRef resource while we're opening the file; we
164  // don't want the plugin destroying it during the Open operation.
165  file_ref_ = enter_file_ref.resource();
166
167  Call<PpapiPluginMsg_FileIO_OpenReply>(BROWSER,
168      PpapiHostMsg_FileIO_Open(
169          file_ref,
170          open_flags),
171      base::Bind(&FileIOResource::OnPluginMsgOpenFileComplete, this,
172                 callback));
173
174  state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_EXCLUSIVE);
175  return PP_OK_COMPLETIONPENDING;
176}
177
178int32_t FileIOResource::Query(PP_FileInfo* info,
179                              scoped_refptr<TrackedCallback> callback) {
180  int32_t rv = state_manager_.CheckOperationState(
181      FileIOStateManager::OPERATION_EXCLUSIVE, true);
182  if (rv != PP_OK)
183    return rv;
184  if (!info)
185    return PP_ERROR_BADARGUMENT;
186  if (!FileHandleHolder::IsValid(file_handle_))
187    return PP_ERROR_FAILED;
188
189  state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_EXCLUSIVE);
190
191  // If the callback is blocking, perform the task on the calling thread.
192  if (callback->is_blocking()) {
193    int32_t result = PP_ERROR_FAILED;
194    base::File::Info file_info;
195    // The plugin could release its reference to this instance when we release
196    // the proxy lock below.
197    scoped_refptr<FileIOResource> protect(this);
198    {
199      // Release the proxy lock while making a potentially slow file call.
200      ProxyAutoUnlock unlock;
201      // TODO(rvargas): Convert this code to base::File.
202      base::File file(file_handle_->raw_handle());
203      bool success = file.GetInfo(&file_info);
204      file.TakePlatformFile();
205      if (success)
206        result = PP_OK;
207    }
208    if (result == PP_OK) {
209      // This writes the file info into the plugin's PP_FileInfo struct.
210      ppapi::FileInfoToPepperFileInfo(file_info,
211                                      file_system_type_,
212                                      info);
213    }
214    state_manager_.SetOperationFinished();
215    return result;
216  }
217
218  // For the non-blocking case, post a task to the file thread and add a
219  // completion task to write the result.
220  scoped_refptr<QueryOp> query_op(new QueryOp(file_handle_));
221  base::PostTaskAndReplyWithResult(
222      PpapiGlobals::Get()->GetFileTaskRunner(),
223      FROM_HERE,
224      Bind(&FileIOResource::QueryOp::DoWork, query_op),
225      RunWhileLocked(Bind(&TrackedCallback::Run, callback)));
226  callback->set_completion_task(
227      Bind(&FileIOResource::OnQueryComplete, this, query_op, info));
228
229  return PP_OK_COMPLETIONPENDING;
230}
231
232int32_t FileIOResource::Touch(PP_Time last_access_time,
233                              PP_Time last_modified_time,
234                              scoped_refptr<TrackedCallback> callback) {
235  int32_t rv = state_manager_.CheckOperationState(
236      FileIOStateManager::OPERATION_EXCLUSIVE, true);
237  if (rv != PP_OK)
238    return rv;
239
240  Call<PpapiPluginMsg_FileIO_GeneralReply>(BROWSER,
241      PpapiHostMsg_FileIO_Touch(last_access_time, last_modified_time),
242      base::Bind(&FileIOResource::OnPluginMsgGeneralComplete, this,
243                 callback));
244
245  state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_EXCLUSIVE);
246  return PP_OK_COMPLETIONPENDING;
247}
248
249int32_t FileIOResource::Read(int64_t offset,
250                             char* buffer,
251                             int32_t bytes_to_read,
252                             scoped_refptr<TrackedCallback> callback) {
253  int32_t rv = state_manager_.CheckOperationState(
254      FileIOStateManager::OPERATION_READ, true);
255  if (rv != PP_OK)
256    return rv;
257
258  PP_ArrayOutput output_adapter;
259  output_adapter.GetDataBuffer = &DummyGetDataBuffer;
260  output_adapter.user_data = buffer;
261  return ReadValidated(offset, bytes_to_read, output_adapter, callback);
262}
263
264int32_t FileIOResource::ReadToArray(int64_t offset,
265                                    int32_t max_read_length,
266                                    PP_ArrayOutput* array_output,
267                                    scoped_refptr<TrackedCallback> callback) {
268  DCHECK(array_output);
269  int32_t rv = state_manager_.CheckOperationState(
270      FileIOStateManager::OPERATION_READ, true);
271  if (rv != PP_OK)
272    return rv;
273
274  return ReadValidated(offset, max_read_length, *array_output, callback);
275}
276
277int32_t FileIOResource::Write(int64_t offset,
278                              const char* buffer,
279                              int32_t bytes_to_write,
280                              scoped_refptr<TrackedCallback> callback) {
281  if (!buffer)
282    return PP_ERROR_FAILED;
283  if (offset < 0 || bytes_to_write < 0)
284    return PP_ERROR_FAILED;
285  if (!FileHandleHolder::IsValid(file_handle_))
286    return PP_ERROR_FAILED;
287
288  int32_t rv = state_manager_.CheckOperationState(
289      FileIOStateManager::OPERATION_WRITE, true);
290  if (rv != PP_OK)
291    return rv;
292
293  state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_WRITE);
294
295  if (check_quota_) {
296    int64_t increase = 0;
297    uint64_t max_offset = 0;
298    bool append = (open_flags_ & PP_FILEOPENFLAG_APPEND) != 0;
299    if (append) {
300      increase = bytes_to_write;
301    } else {
302      uint64_t max_offset = offset + bytes_to_write;
303      if (max_offset > static_cast<uint64_t>(kint64max))
304        return PP_ERROR_FAILED;  // amount calculation would overflow.
305      increase = static_cast<int64_t>(max_offset) - max_written_offset_;
306    }
307
308    if (increase > 0) {
309      int64_t result =
310          file_system_resource_->AsPPB_FileSystem_API()->RequestQuota(
311              increase,
312              base::Bind(&FileIOResource::OnRequestWriteQuotaComplete,
313                         this,
314                         offset, buffer, bytes_to_write, callback));
315      if (result == PP_OK_COMPLETIONPENDING)
316        return PP_OK_COMPLETIONPENDING;
317      DCHECK(result == increase);
318
319      if (append)
320        append_mode_write_amount_ += bytes_to_write;
321      else
322        max_written_offset_ = max_offset;
323    }
324  }
325  return WriteValidated(offset, buffer, bytes_to_write, callback);
326}
327
328int32_t FileIOResource::SetLength(int64_t length,
329                                  scoped_refptr<TrackedCallback> callback) {
330  int32_t rv = state_manager_.CheckOperationState(
331      FileIOStateManager::OPERATION_EXCLUSIVE, true);
332  if (rv != PP_OK)
333    return rv;
334  if (length < 0)
335    return PP_ERROR_FAILED;
336
337  if (check_quota_) {
338    int64_t increase = length - max_written_offset_;
339    if (increase > 0) {
340      int32_t result =
341          file_system_resource_->AsPPB_FileSystem_API()->RequestQuota(
342              increase,
343              base::Bind(&FileIOResource::OnRequestSetLengthQuotaComplete,
344                         this,
345                         length, callback));
346      if (result == PP_OK_COMPLETIONPENDING) {
347        state_manager_.SetPendingOperation(
348            FileIOStateManager::OPERATION_EXCLUSIVE);
349        return PP_OK_COMPLETIONPENDING;
350      }
351      DCHECK(result == increase);
352      max_written_offset_ = length;
353    }
354  }
355
356  state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_EXCLUSIVE);
357  SetLengthValidated(length, callback);
358  return PP_OK_COMPLETIONPENDING;
359}
360
361int32_t FileIOResource::Flush(scoped_refptr<TrackedCallback> callback) {
362  int32_t rv = state_manager_.CheckOperationState(
363      FileIOStateManager::OPERATION_EXCLUSIVE, true);
364  if (rv != PP_OK)
365    return rv;
366
367  Call<PpapiPluginMsg_FileIO_GeneralReply>(BROWSER,
368      PpapiHostMsg_FileIO_Flush(),
369      base::Bind(&FileIOResource::OnPluginMsgGeneralComplete, this,
370                 callback));
371
372  state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_EXCLUSIVE);
373  return PP_OK_COMPLETIONPENDING;
374}
375
376int64_t FileIOResource::GetMaxWrittenOffset() const {
377  return max_written_offset_;
378}
379
380int64_t FileIOResource::GetAppendModeWriteAmount() const {
381  return append_mode_write_amount_;
382}
383
384void FileIOResource::SetMaxWrittenOffset(int64_t max_written_offset) {
385  max_written_offset_ = max_written_offset;
386}
387
388void FileIOResource::SetAppendModeWriteAmount(
389    int64_t append_mode_write_amount) {
390  append_mode_write_amount_ = append_mode_write_amount;
391}
392
393void FileIOResource::Close() {
394  if (called_close_)
395    return;
396
397  called_close_ = true;
398  if (check_quota_) {
399    check_quota_ = false;
400    file_system_resource_->AsPPB_FileSystem_API()->CloseQuotaFile(
401        pp_resource());
402  }
403
404  if (file_handle_)
405    file_handle_ = NULL;
406
407  Post(BROWSER, PpapiHostMsg_FileIO_Close(
408      FileGrowth(max_written_offset_, append_mode_write_amount_)));
409}
410
411int32_t FileIOResource::RequestOSFileHandle(
412    PP_FileHandle* handle,
413    scoped_refptr<TrackedCallback> callback) {
414  int32_t rv = state_manager_.CheckOperationState(
415      FileIOStateManager::OPERATION_EXCLUSIVE, true);
416  if (rv != PP_OK)
417    return rv;
418
419  Call<PpapiPluginMsg_FileIO_RequestOSFileHandleReply>(BROWSER,
420      PpapiHostMsg_FileIO_RequestOSFileHandle(),
421      base::Bind(&FileIOResource::OnPluginMsgRequestOSFileHandleComplete, this,
422                 callback, handle));
423
424  state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_EXCLUSIVE);
425  return PP_OK_COMPLETIONPENDING;
426}
427
428FileIOResource::FileHandleHolder::FileHandleHolder(PP_FileHandle file_handle)
429    : raw_handle_(file_handle) {
430}
431
432// static
433bool FileIOResource::FileHandleHolder::IsValid(
434    const scoped_refptr<FileIOResource::FileHandleHolder>& handle) {
435  return handle && (handle->raw_handle() != base::kInvalidPlatformFileValue);
436}
437
438FileIOResource::FileHandleHolder::~FileHandleHolder() {
439  if (raw_handle_ != base::kInvalidPlatformFileValue) {
440    base::TaskRunner* file_task_runner =
441        PpapiGlobals::Get()->GetFileTaskRunner();
442    file_task_runner->PostTask(FROM_HERE,
443                               base::Bind(&DoClose, raw_handle_));
444  }
445}
446
447int32_t FileIOResource::ReadValidated(int64_t offset,
448                                      int32_t bytes_to_read,
449                                      const PP_ArrayOutput& array_output,
450                                      scoped_refptr<TrackedCallback> callback) {
451  if (bytes_to_read < 0)
452    return PP_ERROR_FAILED;
453  if (!FileHandleHolder::IsValid(file_handle_))
454    return PP_ERROR_FAILED;
455
456  state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_READ);
457
458  bytes_to_read = std::min(bytes_to_read, kMaxReadWriteSize);
459  if (callback->is_blocking()) {
460    char* buffer = static_cast<char*>(
461        array_output.GetDataBuffer(array_output.user_data, bytes_to_read, 1));
462    int32_t result = PP_ERROR_FAILED;
463    // The plugin could release its reference to this instance when we release
464    // the proxy lock below.
465    scoped_refptr<FileIOResource> protect(this);
466    if (buffer) {
467      // Release the proxy lock while making a potentially slow file call.
468      ProxyAutoUnlock unlock;
469      result = base::ReadPlatformFile(
470          file_handle_->raw_handle(), offset, buffer, bytes_to_read);
471      if (result < 0)
472        result = PP_ERROR_FAILED;
473    }
474    state_manager_.SetOperationFinished();
475    return result;
476  }
477
478  // For the non-blocking case, post a task to the file thread.
479  scoped_refptr<ReadOp> read_op(
480      new ReadOp(file_handle_, offset, bytes_to_read));
481  base::PostTaskAndReplyWithResult(
482      PpapiGlobals::Get()->GetFileTaskRunner(),
483      FROM_HERE,
484      Bind(&FileIOResource::ReadOp::DoWork, read_op),
485      RunWhileLocked(Bind(&TrackedCallback::Run, callback)));
486  callback->set_completion_task(
487      Bind(&FileIOResource::OnReadComplete, this, read_op, array_output));
488
489  return PP_OK_COMPLETIONPENDING;
490}
491
492int32_t FileIOResource::WriteValidated(
493    int64_t offset,
494    const char* buffer,
495    int32_t bytes_to_write,
496    scoped_refptr<TrackedCallback> callback) {
497  bool append = (open_flags_ & PP_FILEOPENFLAG_APPEND) != 0;
498  if (callback->is_blocking()) {
499    int32_t result;
500    {
501      // Release the proxy lock while making a potentially slow file call.
502      ProxyAutoUnlock unlock;
503      if (append) {
504        result = base::WritePlatformFileAtCurrentPos(
505            file_handle_->raw_handle(), buffer, bytes_to_write);
506      } else {
507        result = base::WritePlatformFile(
508            file_handle_->raw_handle(), offset, buffer, bytes_to_write);
509      }
510    }
511    if (result < 0)
512      result = PP_ERROR_FAILED;
513
514    state_manager_.SetOperationFinished();
515    return result;
516  }
517
518  // For the non-blocking case, post a task to the file thread.
519  scoped_refptr<WriteOp> write_op(
520      new WriteOp(file_handle_, offset, buffer, bytes_to_write, append));
521  base::PostTaskAndReplyWithResult(
522      PpapiGlobals::Get()->GetFileTaskRunner(),
523      FROM_HERE,
524      Bind(&FileIOResource::WriteOp::DoWork, write_op),
525      RunWhileLocked(Bind(&TrackedCallback::Run, callback)));
526  callback->set_completion_task(
527      Bind(&FileIOResource::OnWriteComplete, this, write_op));
528
529  return PP_OK_COMPLETIONPENDING;
530}
531
532void FileIOResource::SetLengthValidated(
533    int64_t length,
534    scoped_refptr<TrackedCallback> callback) {
535  Call<PpapiPluginMsg_FileIO_GeneralReply>(BROWSER,
536      PpapiHostMsg_FileIO_SetLength(length),
537      base::Bind(&FileIOResource::OnPluginMsgGeneralComplete, this,
538                 callback));
539
540  // On the browser side we grow |max_written_offset_| monotonically, due to the
541  // unpredictable ordering of plugin side Write and SetLength calls. Match that
542  // behavior here.
543  if (max_written_offset_ < length)
544    max_written_offset_ = length;
545}
546
547int32_t FileIOResource::OnQueryComplete(scoped_refptr<QueryOp> query_op,
548                                        PP_FileInfo* info,
549                                        int32_t result) {
550  DCHECK(state_manager_.get_pending_operation() ==
551         FileIOStateManager::OPERATION_EXCLUSIVE);
552
553  if (result == PP_OK) {
554    // This writes the file info into the plugin's PP_FileInfo struct.
555    ppapi::FileInfoToPepperFileInfo(query_op->file_info(),
556                                    file_system_type_,
557                                    info);
558  }
559  state_manager_.SetOperationFinished();
560  return result;
561}
562
563int32_t FileIOResource::OnReadComplete(scoped_refptr<ReadOp> read_op,
564                                       PP_ArrayOutput array_output,
565                                       int32_t result) {
566  DCHECK(state_manager_.get_pending_operation() ==
567         FileIOStateManager::OPERATION_READ);
568  if (result >= 0) {
569    ArrayWriter output;
570    output.set_pp_array_output(array_output);
571    if (output.is_valid())
572      output.StoreArray(read_op->buffer(), result);
573    else
574      result = PP_ERROR_FAILED;
575  } else {
576    // The read operation failed.
577    result = PP_ERROR_FAILED;
578  }
579  state_manager_.SetOperationFinished();
580  return result;
581}
582
583void FileIOResource::OnRequestWriteQuotaComplete(
584    int64_t offset,
585    const char* buffer,
586    int32_t bytes_to_write,
587    scoped_refptr<TrackedCallback> callback,
588    int64_t granted) {
589  DCHECK(granted >= 0);
590  if (granted == 0) {
591    callback->Run(PP_ERROR_NOQUOTA);
592    return;
593  }
594  if (open_flags_ & PP_FILEOPENFLAG_APPEND) {
595    DCHECK_LE(bytes_to_write, granted);
596    append_mode_write_amount_ += bytes_to_write;
597  } else {
598    DCHECK_LE(offset + bytes_to_write - max_written_offset_, granted);
599
600    int64_t max_offset = offset + bytes_to_write;
601    if (max_written_offset_ < max_offset)
602      max_written_offset_ = max_offset;
603  }
604
605  int32_t result = WriteValidated(offset, buffer, bytes_to_write, callback);
606  if (result != PP_OK_COMPLETIONPENDING)
607    callback->Run(result);
608}
609
610void FileIOResource::OnRequestSetLengthQuotaComplete(
611    int64_t length,
612    scoped_refptr<TrackedCallback> callback,
613    int64_t granted) {
614  DCHECK(granted >= 0);
615  if (granted == 0) {
616    callback->Run(PP_ERROR_NOQUOTA);
617    return;
618  }
619
620  DCHECK_LE(length - max_written_offset_, granted);
621  if (max_written_offset_ < length)
622    max_written_offset_ = length;
623  SetLengthValidated(length, callback);
624}
625
626int32_t FileIOResource::OnWriteComplete(scoped_refptr<WriteOp> write_op,
627                                        int32_t result) {
628  DCHECK(state_manager_.get_pending_operation() ==
629         FileIOStateManager::OPERATION_WRITE);
630  // |result| is the return value of WritePlatformFile; -1 indicates failure.
631  if (result < 0)
632    result = PP_ERROR_FAILED;
633
634  state_manager_.SetOperationFinished();
635  return result;
636}
637
638void FileIOResource::OnPluginMsgGeneralComplete(
639    scoped_refptr<TrackedCallback> callback,
640    const ResourceMessageReplyParams& params) {
641  DCHECK(state_manager_.get_pending_operation() ==
642         FileIOStateManager::OPERATION_EXCLUSIVE ||
643         state_manager_.get_pending_operation() ==
644         FileIOStateManager::OPERATION_WRITE);
645  // End this operation now, so the user's callback can execute another FileIO
646  // operation, assuming there are no other pending operations.
647  state_manager_.SetOperationFinished();
648  callback->Run(params.result());
649}
650
651void FileIOResource::OnPluginMsgOpenFileComplete(
652    scoped_refptr<TrackedCallback> callback,
653    const ResourceMessageReplyParams& params,
654    PP_Resource quota_file_system,
655    int64_t max_written_offset) {
656  DCHECK(state_manager_.get_pending_operation() ==
657         FileIOStateManager::OPERATION_EXCLUSIVE);
658
659  // Release the FileRef resource.
660  file_ref_ = NULL;
661  int32_t result = params.result();
662  if (result == PP_OK) {
663    state_manager_.SetOpenSucceed();
664
665    if (quota_file_system) {
666      DCHECK(quota_file_system == file_system_resource_->pp_resource());
667      check_quota_ = true;
668      max_written_offset_ = max_written_offset;
669      file_system_resource_->AsPPB_FileSystem_API()->OpenQuotaFile(
670          pp_resource());
671    }
672
673    IPC::PlatformFileForTransit transit_file;
674    if (params.TakeFileHandleAtIndex(0, &transit_file)) {
675      file_handle_ = new FileHandleHolder(
676          IPC::PlatformFileForTransitToPlatformFile(transit_file));
677    }
678  }
679  // End this operation now, so the user's callback can execute another FileIO
680  // operation, assuming there are no other pending operations.
681  state_manager_.SetOperationFinished();
682  callback->Run(result);
683}
684
685void FileIOResource::OnPluginMsgRequestOSFileHandleComplete(
686    scoped_refptr<TrackedCallback> callback,
687    PP_FileHandle* output_handle,
688    const ResourceMessageReplyParams& params) {
689  DCHECK(state_manager_.get_pending_operation() ==
690         FileIOStateManager::OPERATION_EXCLUSIVE);
691
692  if (!TrackedCallback::IsPending(callback)) {
693    state_manager_.SetOperationFinished();
694    return;
695  }
696
697  int32_t result = params.result();
698  IPC::PlatformFileForTransit transit_file;
699  if (!params.TakeFileHandleAtIndex(0, &transit_file))
700    result = PP_ERROR_FAILED;
701  *output_handle = IPC::PlatformFileForTransitToPlatformFile(transit_file);
702
703  // End this operation now, so the user's callback can execute another FileIO
704  // operation, assuming there are no other pending operations.
705  state_manager_.SetOperationFinished();
706  callback->Run(result);
707}
708
709}  // namespace proxy
710}  // namespace ppapi
711