blob: a35c9ece3d7ebb11169a71e58ebea1bd2c070136 [file] [log] [blame]
[email protected]c77144722013-01-19 04:16:361// 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"
[email protected]914a4ba92013-08-10 13:38:488#include "base/task_runner_util.h"
[email protected]c77144722013-01-19 04:16:369#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"
[email protected]4837a982013-11-25 18:11:1313#include "ppapi/shared_impl/file_ref_create_info.h"
[email protected]26dfb4b72013-11-12 19:36:1314#include "ppapi/shared_impl/file_system_util.h"
[email protected]d45f29b2013-08-09 04:18:0615#include "ppapi/shared_impl/file_type_conversion.h"
[email protected]c77144722013-01-19 04:16:3616#include "ppapi/shared_impl/ppapi_globals.h"
[email protected]d45f29b2013-08-09 04:18:0617#include "ppapi/shared_impl/proxy_lock.h"
[email protected]c77144722013-01-19 04:16:3618#include "ppapi/shared_impl/resource_tracker.h"
19#include "ppapi/thunk/enter.h"
20#include "ppapi/thunk/ppb_file_ref_api.h"
[email protected]3dbfbe512013-12-27 22:53:0021#include "ppapi/thunk/ppb_file_system_api.h"
[email protected]c77144722013-01-19 04:16:3622
23using ppapi::thunk::EnterResourceNoLock;
24using ppapi::thunk::PPB_FileIO_API;
25using ppapi::thunk::PPB_FileRef_API;
[email protected]3dbfbe512013-12-27 22:53:0026using ppapi::thunk::PPB_FileSystem_API;
[email protected]c77144722013-01-19 04:16:3627
28namespace {
29
[email protected]914a4ba92013-08-10 13:38:4830// We must allocate a buffer sized according to the request of the plugin. To
[email protected]6f684412013-12-12 23:18:3731// 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
[email protected]914a4ba92013-08-10 13:38:4835
[email protected]c77144722013-01-19 04:16:3636// 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
[email protected]d45f29b2013-08-09 04:18:0641// File thread task to close the file handle.
42void DoClose(base::PlatformFile file) {
43 base::ClosePlatformFile(file);
44}
45
[email protected]c77144722013-01-19 04:16:3646} // namespace
47
48namespace ppapi {
49namespace proxy {
50
[email protected]d35d3f42013-10-02 19:52:2051FileIOResource::QueryOp::QueryOp(scoped_refptr<FileHandleHolder> file_handle)
[email protected]914a4ba92013-08-10 13:38:4852 : file_handle_(file_handle) {
[email protected]d35d3f42013-10-02 19:52:2053 DCHECK(file_handle_);
[email protected]914a4ba92013-08-10 13:38:4854}
55
56FileIOResource::QueryOp::~QueryOp() {
57}
58
59int32_t FileIOResource::QueryOp::DoWork() {
[email protected]141bcc52014-01-27 21:36:0060 // 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;
[email protected]914a4ba92013-08-10 13:38:4865}
66
[email protected]d35d3f42013-10-02 19:52:2067FileIOResource::ReadOp::ReadOp(scoped_refptr<FileHandleHolder> file_handle,
[email protected]914a4ba92013-08-10 13:38:4868 int64_t offset,
69 int32_t bytes_to_read)
70 : file_handle_(file_handle),
71 offset_(offset),
72 bytes_to_read_(bytes_to_read) {
[email protected]d35d3f42013-10-02 19:52:2073 DCHECK(file_handle_);
[email protected]914a4ba92013-08-10 13:38:4874}
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(
[email protected]d35d3f42013-10-02 19:52:2083 file_handle_->raw_handle(), offset_, buffer_.get(), bytes_to_read_);
[email protected]914a4ba92013-08-10 13:38:4884}
85
[email protected]7a90b852013-12-28 17:54:2786FileIOResource::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
[email protected]c77144722013-01-19 04:16:36113FileIOResource::FileIOResource(Connection connection, PP_Instance instance)
[email protected]d45f29b2013-08-09 04:18:06114 : PluginResource(connection, instance),
[email protected]3dbfbe512013-12-27 22:53:00115 file_system_type_(PP_FILESYSTEMTYPE_INVALID),
[email protected]7a90b852013-12-28 17:54:27116 open_flags_(0),
117 max_written_offset_(0),
[email protected]304875d2014-01-22 10:31:12118 append_mode_write_amount_(0),
[email protected]7a90b852013-12-28 17:54:27119 check_quota_(false),
[email protected]3dbfbe512013-12-27 22:53:00120 called_close_(false) {
[email protected]10c39222013-11-13 20:09:25121 SendCreate(BROWSER, PpapiHostMsg_FileIO_Create());
[email protected]c77144722013-01-19 04:16:36122}
123
124FileIOResource::~FileIOResource() {
[email protected]3dbfbe512013-12-27 22:53:00125 Close();
[email protected]c77144722013-01-19 04:16:36126}
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) {
[email protected]3dbfbe512013-12-27 22:53:00135 EnterResourceNoLock<PPB_FileRef_API> enter_file_ref(file_ref, true);
136 if (enter_file_ref.failed())
[email protected]c77144722013-01-19 04:16:36137 return PP_ERROR_BADRESOURCE;
138
[email protected]3dbfbe512013-12-27 22:53:00139 PPB_FileRef_API* file_ref_api = enter_file_ref.object();
[email protected]4837a982013-11-25 18:11:13140 const FileRefCreateInfo& create_info = file_ref_api->GetCreateInfo();
141 if (!FileSystemTypeIsValid(create_info.file_system_type)) {
[email protected]d45f29b2013-08-09 04:18:06142 NOTREACHED();
143 return PP_ERROR_FAILED;
144 }
[email protected]c77144722013-01-19 04:16:36145 int32_t rv = state_manager_.CheckOperationState(
146 FileIOStateManager::OPERATION_EXCLUSIVE, false);
147 if (rv != PP_OK)
148 return rv;
149
[email protected]7a90b852013-12-28 17:54:27150 open_flags_ = open_flags;
[email protected]4837a982013-11-25 18:11:13151 file_system_type_ = create_info.file_system_type;
[email protected]3dbfbe512013-12-27 22:53:00152
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 }
[email protected]4837a982013-11-25 18:11:13162
[email protected]c6420f082013-09-18 22:42:41163 // 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.
[email protected]3dbfbe512013-12-27 22:53:00165 file_ref_ = enter_file_ref.resource();
[email protected]c6420f082013-09-18 22:42:41166
[email protected]10c39222013-11-13 20:09:25167 Call<PpapiPluginMsg_FileIO_OpenReply>(BROWSER,
[email protected]c77144722013-01-19 04:16:36168 PpapiHostMsg_FileIO_Open(
[email protected]c6420f082013-09-18 22:42:41169 file_ref,
[email protected]c77144722013-01-19 04:16:36170 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;
[email protected]914a4ba92013-08-10 13:38:48184 if (!info)
185 return PP_ERROR_BADARGUMENT;
[email protected]d35d3f42013-10-02 19:52:20186 if (!FileHandleHolder::IsValid(file_handle_))
[email protected]914a4ba92013-08-10 13:38:48187 return PP_ERROR_FAILED;
[email protected]c77144722013-01-19 04:16:36188
189 state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_EXCLUSIVE);
[email protected]914a4ba92013-08-10 13:38:48190
191 // If the callback is blocking, perform the task on the calling thread.
192 if (callback->is_blocking()) {
[email protected]452fb142013-10-23 01:49:43193 int32_t result = PP_ERROR_FAILED;
[email protected]141bcc52014-01-27 21:36:00194 base::File::Info file_info;
[email protected]452fb142013-10-23 01:49:43195 // The plugin could release its reference to this instance when we release
196 // the proxy lock below.
197 scoped_refptr<FileIOResource> protect(this);
[email protected]914a4ba92013-08-10 13:38:48198 {
199 // Release the proxy lock while making a potentially slow file call.
200 ProxyAutoUnlock unlock;
[email protected]141bcc52014-01-27 21:36:00201 // 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)
[email protected]452fb142013-10-23 01:49:43206 result = PP_OK;
[email protected]914a4ba92013-08-10 13:38:48207 }
[email protected]452fb142013-10-23 01:49:43208 if (result == PP_OK) {
209 // This writes the file info into the plugin's PP_FileInfo struct.
[email protected]141bcc52014-01-27 21:36:00210 ppapi::FileInfoToPepperFileInfo(file_info,
211 file_system_type_,
212 info);
[email protected]452fb142013-10-23 01:49:43213 }
214 state_manager_.SetOperationFinished();
215 return result;
[email protected]914a4ba92013-08-10 13:38:48216 }
217
218 // For the non-blocking case, post a task to the file thread and add a
219 // completion task to write the result.
[email protected]452fb142013-10-23 01:49:43220 scoped_refptr<QueryOp> query_op(new QueryOp(file_handle_));
[email protected]914a4ba92013-08-10 13:38:48221 base::PostTaskAndReplyWithResult(
[email protected]3b5c68582013-10-01 06:20:44222 PpapiGlobals::Get()->GetFileTaskRunner(),
[email protected]914a4ba92013-08-10 13:38:48223 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
[email protected]c77144722013-01-19 04:16:36229 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
[email protected]10c39222013-11-13 20:09:25240 Call<PpapiPluginMsg_FileIO_GeneralReply>(BROWSER,
[email protected]c77144722013-01-19 04:16:36241 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;
[email protected]c77144722013-01-19 04:16:36261 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
[email protected]c77144722013-01-19 04:16:36274 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) {
[email protected]7a90b852013-12-28 17:54:27281 if (!buffer)
282 return PP_ERROR_FAILED;
[email protected]304875d2014-01-22 10:31:12283 if (offset < 0 || bytes_to_write < 0)
[email protected]7a90b852013-12-28 17:54:27284 return PP_ERROR_FAILED;
285 if (!FileHandleHolder::IsValid(file_handle_))
286 return PP_ERROR_FAILED;
287
[email protected]c77144722013-01-19 04:16:36288 int32_t rv = state_manager_.CheckOperationState(
289 FileIOStateManager::OPERATION_WRITE, true);
290 if (rv != PP_OK)
291 return rv;
292
[email protected]c77144722013-01-19 04:16:36293 state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_WRITE);
[email protected]7a90b852013-12-28 17:54:27294
295 if (check_quota_) {
[email protected]304875d2014-01-22 10:31:12296 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 }
[email protected]7a90b852013-12-28 17:54:27307
[email protected]7a90b852013-12-28 17:54:27308 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);
[email protected]304875d2014-01-22 10:31:12318
319 if (append)
320 append_mode_write_amount_ += bytes_to_write;
321 else
322 max_written_offset_ = max_offset;
[email protected]7a90b852013-12-28 17:54:27323 }
324 }
325 return WriteValidated(offset, buffer, bytes_to_write, callback);
[email protected]c77144722013-01-19 04:16:36326}
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;
[email protected]7a90b852013-12-28 17:54:27334 if (length < 0)
335 return PP_ERROR_FAILED;
[email protected]c77144722013-01-19 04:16:36336
[email protected]7a90b852013-12-28 17:54:27337 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 }
[email protected]c77144722013-01-19 04:16:36355
356 state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_EXCLUSIVE);
[email protected]7a90b852013-12-28 17:54:27357 SetLengthValidated(length, callback);
[email protected]c77144722013-01-19 04:16:36358 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
[email protected]10c39222013-11-13 20:09:25367 Call<PpapiPluginMsg_FileIO_GeneralReply>(BROWSER,
[email protected]c77144722013-01-19 04:16:36368 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
[email protected]7a90b852013-12-28 17:54:27376int64_t FileIOResource::GetMaxWrittenOffset() const {
377 return max_written_offset_;
378}
379
[email protected]304875d2014-01-22 10:31:12380int64_t FileIOResource::GetAppendModeWriteAmount() const {
381 return append_mode_write_amount_;
382}
383
[email protected]7a90b852013-12-28 17:54:27384void FileIOResource::SetMaxWrittenOffset(int64_t max_written_offset) {
385 max_written_offset_ = max_written_offset;
386}
387
[email protected]304875d2014-01-22 10:31:12388void FileIOResource::SetAppendModeWriteAmount(
389 int64_t append_mode_write_amount) {
390 append_mode_write_amount_ = append_mode_write_amount;
391}
392
[email protected]c77144722013-01-19 04:16:36393void FileIOResource::Close() {
[email protected]3dbfbe512013-12-27 22:53:00394 if (called_close_)
395 return;
396
397 called_close_ = true;
[email protected]7a90b852013-12-28 17:54:27398 if (check_quota_) {
399 check_quota_ = false;
400 file_system_resource_->AsPPB_FileSystem_API()->CloseQuotaFile(
401 pp_resource());
402 }
403
[email protected]3dbfbe512013-12-27 22:53:00404 if (file_handle_)
[email protected]d35d3f42013-10-02 19:52:20405 file_handle_ = NULL;
[email protected]3dbfbe512013-12-27 22:53:00406
[email protected]304875d2014-01-22 10:31:12407 // TODO(tzik): Post |max_written_offset_| and |append_mode_write_amount_|
408 // separately by using FileGrowth after the IPC signature changed.
409 Post(BROWSER, PpapiHostMsg_FileIO_Close(
410 max_written_offset_ + append_mode_write_amount_));
[email protected]c77144722013-01-19 04:16:36411}
412
[email protected]8f96cef2013-04-01 16:51:13413int32_t FileIOResource::RequestOSFileHandle(
414 PP_FileHandle* handle,
415 scoped_refptr<TrackedCallback> callback) {
416 int32_t rv = state_manager_.CheckOperationState(
417 FileIOStateManager::OPERATION_EXCLUSIVE, true);
418 if (rv != PP_OK)
419 return rv;
420
[email protected]10c39222013-11-13 20:09:25421 Call<PpapiPluginMsg_FileIO_RequestOSFileHandleReply>(BROWSER,
[email protected]8f96cef2013-04-01 16:51:13422 PpapiHostMsg_FileIO_RequestOSFileHandle(),
423 base::Bind(&FileIOResource::OnPluginMsgRequestOSFileHandleComplete, this,
424 callback, handle));
425
426 state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_EXCLUSIVE);
427 return PP_OK_COMPLETIONPENDING;
428}
429
[email protected]d35d3f42013-10-02 19:52:20430FileIOResource::FileHandleHolder::FileHandleHolder(PP_FileHandle file_handle)
431 : raw_handle_(file_handle) {
432}
433
434// static
435bool FileIOResource::FileHandleHolder::IsValid(
436 const scoped_refptr<FileIOResource::FileHandleHolder>& handle) {
437 return handle && (handle->raw_handle() != base::kInvalidPlatformFileValue);
438}
439
440FileIOResource::FileHandleHolder::~FileHandleHolder() {
441 if (raw_handle_ != base::kInvalidPlatformFileValue) {
442 base::TaskRunner* file_task_runner =
443 PpapiGlobals::Get()->GetFileTaskRunner();
444 file_task_runner->PostTask(FROM_HERE,
445 base::Bind(&DoClose, raw_handle_));
446 }
447}
448
[email protected]d45f29b2013-08-09 04:18:06449int32_t FileIOResource::ReadValidated(int64_t offset,
450 int32_t bytes_to_read,
451 const PP_ArrayOutput& array_output,
452 scoped_refptr<TrackedCallback> callback) {
[email protected]914a4ba92013-08-10 13:38:48453 if (bytes_to_read < 0)
454 return PP_ERROR_FAILED;
[email protected]d35d3f42013-10-02 19:52:20455 if (!FileHandleHolder::IsValid(file_handle_))
[email protected]914a4ba92013-08-10 13:38:48456 return PP_ERROR_FAILED;
457
[email protected]d45f29b2013-08-09 04:18:06458 state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_READ);
459
[email protected]6f684412013-12-12 23:18:37460 bytes_to_read = std::min(bytes_to_read, kMaxReadWriteSize);
[email protected]914a4ba92013-08-10 13:38:48461 if (callback->is_blocking()) {
[email protected]452fb142013-10-23 01:49:43462 char* buffer = static_cast<char*>(
463 array_output.GetDataBuffer(array_output.user_data, bytes_to_read, 1));
464 int32_t result = PP_ERROR_FAILED;
465 // The plugin could release its reference to this instance when we release
466 // the proxy lock below.
467 scoped_refptr<FileIOResource> protect(this);
468 if (buffer) {
[email protected]914a4ba92013-08-10 13:38:48469 // Release the proxy lock while making a potentially slow file call.
470 ProxyAutoUnlock unlock;
[email protected]452fb142013-10-23 01:49:43471 result = base::ReadPlatformFile(
472 file_handle_->raw_handle(), offset, buffer, bytes_to_read);
473 if (result < 0)
474 result = PP_ERROR_FAILED;
[email protected]d45f29b2013-08-09 04:18:06475 }
[email protected]452fb142013-10-23 01:49:43476 state_manager_.SetOperationFinished();
477 return result;
[email protected]d45f29b2013-08-09 04:18:06478 }
479
[email protected]914a4ba92013-08-10 13:38:48480 // For the non-blocking case, post a task to the file thread.
[email protected]452fb142013-10-23 01:49:43481 scoped_refptr<ReadOp> read_op(
482 new ReadOp(file_handle_, offset, bytes_to_read));
[email protected]914a4ba92013-08-10 13:38:48483 base::PostTaskAndReplyWithResult(
[email protected]3b5c68582013-10-01 06:20:44484 PpapiGlobals::Get()->GetFileTaskRunner(),
[email protected]914a4ba92013-08-10 13:38:48485 FROM_HERE,
486 Bind(&FileIOResource::ReadOp::DoWork, read_op),
487 RunWhileLocked(Bind(&TrackedCallback::Run, callback)));
488 callback->set_completion_task(
489 Bind(&FileIOResource::OnReadComplete, this, read_op, array_output));
490
[email protected]d45f29b2013-08-09 04:18:06491 return PP_OK_COMPLETIONPENDING;
492}
493
[email protected]7a90b852013-12-28 17:54:27494int32_t FileIOResource::WriteValidated(
495 int64_t offset,
496 const char* buffer,
497 int32_t bytes_to_write,
498 scoped_refptr<TrackedCallback> callback) {
499 bool append = (open_flags_ & PP_FILEOPENFLAG_APPEND) != 0;
500 if (callback->is_blocking()) {
501 int32_t result;
502 {
503 // Release the proxy lock while making a potentially slow file call.
504 ProxyAutoUnlock unlock;
505 if (append) {
506 result = base::WritePlatformFileAtCurrentPos(
507 file_handle_->raw_handle(), buffer, bytes_to_write);
508 } else {
509 result = base::WritePlatformFile(
510 file_handle_->raw_handle(), offset, buffer, bytes_to_write);
511 }
512 }
513 if (result < 0)
514 result = PP_ERROR_FAILED;
515
516 state_manager_.SetOperationFinished();
517 return result;
518 }
519
520 // For the non-blocking case, post a task to the file thread.
521 scoped_refptr<WriteOp> write_op(
522 new WriteOp(file_handle_, offset, buffer, bytes_to_write, append));
523 base::PostTaskAndReplyWithResult(
524 PpapiGlobals::Get()->GetFileTaskRunner(),
525 FROM_HERE,
526 Bind(&FileIOResource::WriteOp::DoWork, write_op),
527 RunWhileLocked(Bind(&TrackedCallback::Run, callback)));
528 callback->set_completion_task(
529 Bind(&FileIOResource::OnWriteComplete, this, write_op));
530
531 return PP_OK_COMPLETIONPENDING;
532}
533
534void FileIOResource::SetLengthValidated(
535 int64_t length,
536 scoped_refptr<TrackedCallback> callback) {
537 Call<PpapiPluginMsg_FileIO_GeneralReply>(BROWSER,
538 PpapiHostMsg_FileIO_SetLength(length),
539 base::Bind(&FileIOResource::OnPluginMsgGeneralComplete, this,
540 callback));
541
[email protected]304875d2014-01-22 10:31:12542 // On the browser side we grow |max_written_offset_| monotonically, due to the
543 // unpredictable ordering of plugin side Write and SetLength calls. Match that
544 // behavior here.
545 if (max_written_offset_ < length)
546 max_written_offset_ = length;
[email protected]7a90b852013-12-28 17:54:27547}
548
[email protected]914a4ba92013-08-10 13:38:48549int32_t FileIOResource::OnQueryComplete(scoped_refptr<QueryOp> query_op,
550 PP_FileInfo* info,
551 int32_t result) {
552 DCHECK(state_manager_.get_pending_operation() ==
553 FileIOStateManager::OPERATION_EXCLUSIVE);
554
555 if (result == PP_OK) {
556 // This writes the file info into the plugin's PP_FileInfo struct.
[email protected]141bcc52014-01-27 21:36:00557 ppapi::FileInfoToPepperFileInfo(query_op->file_info(),
558 file_system_type_,
559 info);
[email protected]914a4ba92013-08-10 13:38:48560 }
561 state_manager_.SetOperationFinished();
562 return result;
563}
564
565int32_t FileIOResource::OnReadComplete(scoped_refptr<ReadOp> read_op,
566 PP_ArrayOutput array_output,
567 int32_t result) {
568 DCHECK(state_manager_.get_pending_operation() ==
569 FileIOStateManager::OPERATION_READ);
570 if (result >= 0) {
571 ArrayWriter output;
572 output.set_pp_array_output(array_output);
573 if (output.is_valid())
574 output.StoreArray(read_op->buffer(), result);
575 else
576 result = PP_ERROR_FAILED;
577 } else {
578 // The read operation failed.
579 result = PP_ERROR_FAILED;
580 }
581 state_manager_.SetOperationFinished();
582 return result;
583}
584
[email protected]7a90b852013-12-28 17:54:27585void FileIOResource::OnRequestWriteQuotaComplete(
586 int64_t offset,
587 const char* buffer,
588 int32_t bytes_to_write,
589 scoped_refptr<TrackedCallback> callback,
590 int64_t granted) {
591 DCHECK(granted >= 0);
592 if (granted == 0) {
593 callback->Run(PP_ERROR_NOQUOTA);
594 return;
595 }
[email protected]304875d2014-01-22 10:31:12596 if (open_flags_ & PP_FILEOPENFLAG_APPEND) {
597 DCHECK_LE(bytes_to_write, granted);
598 append_mode_write_amount_ += bytes_to_write;
599 } else {
600 DCHECK_LE(offset + bytes_to_write - max_written_offset_, granted);
601
602 int64_t max_offset = offset + bytes_to_write;
603 if (max_written_offset_ < max_offset)
604 max_written_offset_ = max_offset;
605 }
606
[email protected]7a90b852013-12-28 17:54:27607 int32_t result = WriteValidated(offset, buffer, bytes_to_write, callback);
608 if (result != PP_OK_COMPLETIONPENDING)
609 callback->Run(result);
610}
611
612void FileIOResource::OnRequestSetLengthQuotaComplete(
613 int64_t length,
614 scoped_refptr<TrackedCallback> callback,
615 int64_t granted) {
616 DCHECK(granted >= 0);
617 if (granted == 0) {
618 callback->Run(PP_ERROR_NOQUOTA);
619 return;
620 }
621
[email protected]304875d2014-01-22 10:31:12622 DCHECK_LE(length - max_written_offset_, granted);
623 if (max_written_offset_ < length)
624 max_written_offset_ = length;
[email protected]7a90b852013-12-28 17:54:27625 SetLengthValidated(length, callback);
626}
627
628int32_t FileIOResource::OnWriteComplete(scoped_refptr<WriteOp> write_op,
629 int32_t result) {
630 DCHECK(state_manager_.get_pending_operation() ==
631 FileIOStateManager::OPERATION_WRITE);
632 // |result| is the return value of WritePlatformFile; -1 indicates failure.
633 if (result < 0)
634 result = PP_ERROR_FAILED;
635
636 state_manager_.SetOperationFinished();
637 return result;
638}
639
[email protected]c77144722013-01-19 04:16:36640void FileIOResource::OnPluginMsgGeneralComplete(
641 scoped_refptr<TrackedCallback> callback,
642 const ResourceMessageReplyParams& params) {
643 DCHECK(state_manager_.get_pending_operation() ==
644 FileIOStateManager::OPERATION_EXCLUSIVE ||
645 state_manager_.get_pending_operation() ==
646 FileIOStateManager::OPERATION_WRITE);
[email protected]d45f29b2013-08-09 04:18:06647 // End this operation now, so the user's callback can execute another FileIO
648 // operation, assuming there are no other pending operations.
[email protected]c77144722013-01-19 04:16:36649 state_manager_.SetOperationFinished();
650 callback->Run(params.result());
651}
652
653void FileIOResource::OnPluginMsgOpenFileComplete(
654 scoped_refptr<TrackedCallback> callback,
[email protected]7a90b852013-12-28 17:54:27655 const ResourceMessageReplyParams& params,
656 PP_Resource quota_file_system,
657 int64_t max_written_offset) {
[email protected]c77144722013-01-19 04:16:36658 DCHECK(state_manager_.get_pending_operation() ==
659 FileIOStateManager::OPERATION_EXCLUSIVE);
[email protected]c6420f082013-09-18 22:42:41660
661 // Release the FileRef resource.
662 file_ref_ = NULL;
[email protected]7a90b852013-12-28 17:54:27663 int32_t result = params.result();
664 if (result == PP_OK) {
[email protected]c77144722013-01-19 04:16:36665 state_manager_.SetOpenSucceed();
[email protected]d45f29b2013-08-09 04:18:06666
[email protected]7a90b852013-12-28 17:54:27667 if (quota_file_system) {
668 DCHECK(quota_file_system == file_system_resource_->pp_resource());
669 check_quota_ = true;
670 max_written_offset_ = max_written_offset;
671 file_system_resource_->AsPPB_FileSystem_API()->OpenQuotaFile(
672 pp_resource());
673 }
674
675 IPC::PlatformFileForTransit transit_file;
676 if (params.TakeFileHandleAtIndex(0, &transit_file)) {
677 file_handle_ = new FileHandleHolder(
678 IPC::PlatformFileForTransitToPlatformFile(transit_file));
679 }
[email protected]d35d3f42013-10-02 19:52:20680 }
[email protected]d45f29b2013-08-09 04:18:06681 // End this operation now, so the user's callback can execute another FileIO
682 // operation, assuming there are no other pending operations.
[email protected]23e78de2013-07-26 20:28:47683 state_manager_.SetOperationFinished();
[email protected]d45f29b2013-08-09 04:18:06684 callback->Run(result);
[email protected]23e78de2013-07-26 20:28:47685}
686
[email protected]8f96cef2013-04-01 16:51:13687void FileIOResource::OnPluginMsgRequestOSFileHandleComplete(
688 scoped_refptr<TrackedCallback> callback,
689 PP_FileHandle* output_handle,
690 const ResourceMessageReplyParams& params) {
691 DCHECK(state_manager_.get_pending_operation() ==
692 FileIOStateManager::OPERATION_EXCLUSIVE);
693
694 if (!TrackedCallback::IsPending(callback)) {
695 state_manager_.SetOperationFinished();
696 return;
697 }
698
699 int32_t result = params.result();
700 IPC::PlatformFileForTransit transit_file;
701 if (!params.TakeFileHandleAtIndex(0, &transit_file))
702 result = PP_ERROR_FAILED;
703 *output_handle = IPC::PlatformFileForTransitToPlatformFile(transit_file);
704
[email protected]d45f29b2013-08-09 04:18:06705 // End this operation now, so the user's callback can execute another FileIO
706 // operation, assuming there are no other pending operations.
[email protected]8f96cef2013-04-01 16:51:13707 state_manager_.SetOperationFinished();
708 callback->Run(result);
709}
710
[email protected]c77144722013-01-19 04:16:36711} // namespace proxy
712} // namespace ppapi