715757421e1ed326aa235622e881231c0825cead
[platform/framework/web/crosswalk.git] / src / ppapi / proxy / file_io_resource.cc
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
23 using ppapi::thunk::EnterResourceNoLock;
24 using ppapi::thunk::PPB_FileIO_API;
25 using ppapi::thunk::PPB_FileRef_API;
26 using ppapi::thunk::PPB_FileSystem_API;
27
28 namespace {
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.
34 static const int32_t kMaxReadWriteSize = 32 * 1024 * 1024;  // 32MB
35
36 // An adapter to let Read() share the same implementation with ReadToArray().
37 void* 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.
42 void DoClose(base::PlatformFile file) {
43   base::ClosePlatformFile(file);
44 }
45
46 }  // namespace
47
48 namespace ppapi {
49 namespace proxy {
50
51 FileIOResource::QueryOp::QueryOp(scoped_refptr<FileHandleHolder> file_handle)
52     : file_handle_(file_handle) {
53   DCHECK(file_handle_);
54 }
55
56 FileIOResource::QueryOp::~QueryOp() {
57 }
58
59 int32_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
67 FileIOResource::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
76 FileIOResource::ReadOp::~ReadOp() {
77 }
78
79 int32_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
86 FileIOResource::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
98 FileIOResource::WriteOp::~WriteOp() {
99 }
100
101 int32_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
113 FileIOResource::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
124 FileIOResource::~FileIOResource() {
125   Close();
126 }
127
128 PPB_FileIO_API* FileIOResource::AsPPB_FileIO_API() {
129   return this;
130 }
131
132 int32_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
178 int32_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
232 int32_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
249 int32_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
264 int32_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
277 int32_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
328 int32_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
361 int32_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
376 int64_t FileIOResource::GetMaxWrittenOffset() const {
377   return max_written_offset_;
378 }
379
380 int64_t FileIOResource::GetAppendModeWriteAmount() const {
381   return append_mode_write_amount_;
382 }
383
384 void FileIOResource::SetMaxWrittenOffset(int64_t max_written_offset) {
385   max_written_offset_ = max_written_offset;
386 }
387
388 void FileIOResource::SetAppendModeWriteAmount(
389     int64_t append_mode_write_amount) {
390   append_mode_write_amount_ = append_mode_write_amount;
391 }
392
393 void 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
411 int32_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
428 FileIOResource::FileHandleHolder::FileHandleHolder(PP_FileHandle file_handle)
429     : raw_handle_(file_handle) {
430 }
431
432 // static
433 bool FileIOResource::FileHandleHolder::IsValid(
434     const scoped_refptr<FileIOResource::FileHandleHolder>& handle) {
435   return handle && (handle->raw_handle() != base::kInvalidPlatformFileValue);
436 }
437
438 FileIOResource::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
447 int32_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
492 int32_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
532 void 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
547 int32_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
563 int32_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
583 void 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
610 void 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
626 int32_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
638 void 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
651 void 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
685 void 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