blob: 4a63768cbf12049ebed871b66f9a2bee10e06e88 [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
avidd4e614352015-12-09 00:44:497#include <limits>
dchengd2b9f612015-12-18 19:08:518#include <utility>
avidd4e614352015-12-09 00:44:499
[email protected]c77144722013-01-19 04:16:3610#include "base/bind.h"
[email protected]914a4ba92013-08-10 13:38:4811#include "base/task_runner_util.h"
[email protected]c77144722013-01-19 04:16:3612#include "ipc/ipc_message.h"
13#include "ppapi/c/pp_errors.h"
14#include "ppapi/proxy/ppapi_messages.h"
15#include "ppapi/shared_impl/array_writer.h"
[email protected]4837a982013-11-25 18:11:1316#include "ppapi/shared_impl/file_ref_create_info.h"
[email protected]26dfb4b72013-11-12 19:36:1317#include "ppapi/shared_impl/file_system_util.h"
[email protected]d45f29b2013-08-09 04:18:0618#include "ppapi/shared_impl/file_type_conversion.h"
[email protected]c77144722013-01-19 04:16:3619#include "ppapi/shared_impl/ppapi_globals.h"
[email protected]d45f29b2013-08-09 04:18:0620#include "ppapi/shared_impl/proxy_lock.h"
[email protected]c77144722013-01-19 04:16:3621#include "ppapi/shared_impl/resource_tracker.h"
22#include "ppapi/thunk/enter.h"
23#include "ppapi/thunk/ppb_file_ref_api.h"
[email protected]3dbfbe512013-12-27 22:53:0024#include "ppapi/thunk/ppb_file_system_api.h"
[email protected]c77144722013-01-19 04:16:3625
26using ppapi::thunk::EnterResourceNoLock;
27using ppapi::thunk::PPB_FileIO_API;
28using ppapi::thunk::PPB_FileRef_API;
[email protected]3dbfbe512013-12-27 22:53:0029using ppapi::thunk::PPB_FileSystem_API;
[email protected]c77144722013-01-19 04:16:3630
31namespace {
32
[email protected]914a4ba92013-08-10 13:38:4833// We must allocate a buffer sized according to the request of the plugin. To
[email protected]6f684412013-12-12 23:18:3734// reduce the chance of out-of-memory errors, we cap the read and write size to
35// 32MB. This is OK since the API specifies that it may perform a partial read
36// or write.
37static const int32_t kMaxReadWriteSize = 32 * 1024 * 1024; // 32MB
[email protected]914a4ba92013-08-10 13:38:4838
[email protected]c77144722013-01-19 04:16:3639// An adapter to let Read() share the same implementation with ReadToArray().
40void* DummyGetDataBuffer(void* user_data, uint32_t count, uint32_t size) {
41 return user_data;
42}
43
[email protected]d45f29b2013-08-09 04:18:0644// File thread task to close the file handle.
[email protected]35b05b12014-06-03 00:01:0345void DoClose(base::File auto_close_file) {
[email protected]d45f29b2013-08-09 04:18:0646}
47
[email protected]c77144722013-01-19 04:16:3648} // namespace
49
50namespace ppapi {
51namespace proxy {
52
[email protected]35b05b12014-06-03 00:01:0353FileIOResource::QueryOp::QueryOp(scoped_refptr<FileHolder> file_holder)
54 : file_holder_(file_holder) {
Daniel Cheng6d3ae972014-08-26 00:27:3855 DCHECK(file_holder_.get());
[email protected]914a4ba92013-08-10 13:38:4856}
57
58FileIOResource::QueryOp::~QueryOp() {
59}
60
61int32_t FileIOResource::QueryOp::DoWork() {
[email protected]35b05b12014-06-03 00:01:0362 return file_holder_->file()->GetInfo(&file_info_) ? PP_OK : PP_ERROR_FAILED;
[email protected]914a4ba92013-08-10 13:38:4863}
64
[email protected]35b05b12014-06-03 00:01:0365FileIOResource::ReadOp::ReadOp(scoped_refptr<FileHolder> file_holder,
[email protected]914a4ba92013-08-10 13:38:4866 int64_t offset,
67 int32_t bytes_to_read)
[email protected]35b05b12014-06-03 00:01:0368 : file_holder_(file_holder),
[email protected]914a4ba92013-08-10 13:38:4869 offset_(offset),
70 bytes_to_read_(bytes_to_read) {
Daniel Cheng6d3ae972014-08-26 00:27:3871 DCHECK(file_holder_.get());
[email protected]914a4ba92013-08-10 13:38:4872}
73
74FileIOResource::ReadOp::~ReadOp() {
75}
76
77int32_t FileIOResource::ReadOp::DoWork() {
78 DCHECK(!buffer_.get());
79 buffer_.reset(new char[bytes_to_read_]);
[email protected]35b05b12014-06-03 00:01:0380 return file_holder_->file()->Read(offset_, buffer_.get(), bytes_to_read_);
[email protected]914a4ba92013-08-10 13:38:4881}
82
[email protected]35b05b12014-06-03 00:01:0383FileIOResource::WriteOp::WriteOp(scoped_refptr<FileHolder> file_holder,
[email protected]7a90b852013-12-28 17:54:2784 int64_t offset,
dchengced92242016-04-07 00:00:1285 std::unique_ptr<char[]> buffer,
[email protected]7a90b852013-12-28 17:54:2786 int32_t bytes_to_write,
87 bool append)
[email protected]35b05b12014-06-03 00:01:0388 : file_holder_(file_holder),
[email protected]6c644b7e2014-05-22 06:25:1889 offset_(offset),
dchengd2b9f612015-12-18 19:08:5190 buffer_(std::move(buffer)),
[email protected]6c644b7e2014-05-22 06:25:1891 bytes_to_write_(bytes_to_write),
dchengd2b9f612015-12-18 19:08:5192 append_(append) {}
[email protected]7a90b852013-12-28 17:54:2793
94FileIOResource::WriteOp::~WriteOp() {
95}
96
97int32_t FileIOResource::WriteOp::DoWork() {
[email protected]2c288ed2014-06-05 22:07:4198 // In append mode, we can't call Write, since NaCl doesn't implement fcntl,
99 // causing the function to call pwrite, which is incorrect.
[email protected]7a90b852013-12-28 17:54:27100 if (append_) {
[email protected]35b05b12014-06-03 00:01:03101 return file_holder_->file()->WriteAtCurrentPos(buffer_.get(),
102 bytes_to_write_);
[email protected]7a90b852013-12-28 17:54:27103 } else {
[email protected]35b05b12014-06-03 00:01:03104 return file_holder_->file()->Write(offset_, buffer_.get(), bytes_to_write_);
[email protected]7a90b852013-12-28 17:54:27105 }
106}
107
[email protected]c77144722013-01-19 04:16:36108FileIOResource::FileIOResource(Connection connection, PP_Instance instance)
[email protected]d45f29b2013-08-09 04:18:06109 : PluginResource(connection, instance),
[email protected]3dbfbe512013-12-27 22:53:00110 file_system_type_(PP_FILESYSTEMTYPE_INVALID),
[email protected]7a90b852013-12-28 17:54:27111 open_flags_(0),
112 max_written_offset_(0),
[email protected]304875d2014-01-22 10:31:12113 append_mode_write_amount_(0),
[email protected]7a90b852013-12-28 17:54:27114 check_quota_(false),
[email protected]3dbfbe512013-12-27 22:53:00115 called_close_(false) {
[email protected]10c39222013-11-13 20:09:25116 SendCreate(BROWSER, PpapiHostMsg_FileIO_Create());
[email protected]c77144722013-01-19 04:16:36117}
118
119FileIOResource::~FileIOResource() {
[email protected]3dbfbe512013-12-27 22:53:00120 Close();
[email protected]c77144722013-01-19 04:16:36121}
122
123PPB_FileIO_API* FileIOResource::AsPPB_FileIO_API() {
124 return this;
125}
126
127int32_t FileIOResource::Open(PP_Resource file_ref,
128 int32_t open_flags,
129 scoped_refptr<TrackedCallback> callback) {
[email protected]3dbfbe512013-12-27 22:53:00130 EnterResourceNoLock<PPB_FileRef_API> enter_file_ref(file_ref, true);
131 if (enter_file_ref.failed())
[email protected]c77144722013-01-19 04:16:36132 return PP_ERROR_BADRESOURCE;
133
[email protected]3dbfbe512013-12-27 22:53:00134 PPB_FileRef_API* file_ref_api = enter_file_ref.object();
[email protected]4837a982013-11-25 18:11:13135 const FileRefCreateInfo& create_info = file_ref_api->GetCreateInfo();
136 if (!FileSystemTypeIsValid(create_info.file_system_type)) {
[email protected]d45f29b2013-08-09 04:18:06137 NOTREACHED();
138 return PP_ERROR_FAILED;
139 }
[email protected]c77144722013-01-19 04:16:36140 int32_t rv = state_manager_.CheckOperationState(
141 FileIOStateManager::OPERATION_EXCLUSIVE, false);
142 if (rv != PP_OK)
143 return rv;
144
[email protected]7a90b852013-12-28 17:54:27145 open_flags_ = open_flags;
[email protected]4837a982013-11-25 18:11:13146 file_system_type_ = create_info.file_system_type;
[email protected]3dbfbe512013-12-27 22:53:00147
148 if (create_info.file_system_plugin_resource) {
149 EnterResourceNoLock<PPB_FileSystem_API> enter_file_system(
150 create_info.file_system_plugin_resource, true);
151 if (enter_file_system.failed())
152 return PP_ERROR_FAILED;
153 // Take a reference on the FileSystem resource. The FileIO host uses the
154 // FileSystem host for running tasks and checking quota.
155 file_system_resource_ = enter_file_system.resource();
156 }
[email protected]4837a982013-11-25 18:11:13157
[email protected]c6420f082013-09-18 22:42:41158 // Take a reference on the FileRef resource while we're opening the file; we
159 // don't want the plugin destroying it during the Open operation.
[email protected]3dbfbe512013-12-27 22:53:00160 file_ref_ = enter_file_ref.resource();
[email protected]c6420f082013-09-18 22:42:41161
[email protected]10c39222013-11-13 20:09:25162 Call<PpapiPluginMsg_FileIO_OpenReply>(BROWSER,
[email protected]c77144722013-01-19 04:16:36163 PpapiHostMsg_FileIO_Open(
[email protected]c6420f082013-09-18 22:42:41164 file_ref,
[email protected]c77144722013-01-19 04:16:36165 open_flags),
166 base::Bind(&FileIOResource::OnPluginMsgOpenFileComplete, this,
167 callback));
168
169 state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_EXCLUSIVE);
170 return PP_OK_COMPLETIONPENDING;
171}
172
173int32_t FileIOResource::Query(PP_FileInfo* info,
174 scoped_refptr<TrackedCallback> callback) {
175 int32_t rv = state_manager_.CheckOperationState(
176 FileIOStateManager::OPERATION_EXCLUSIVE, true);
177 if (rv != PP_OK)
178 return rv;
[email protected]914a4ba92013-08-10 13:38:48179 if (!info)
180 return PP_ERROR_BADARGUMENT;
[email protected]35b05b12014-06-03 00:01:03181 if (!FileHolder::IsValid(file_holder_))
[email protected]914a4ba92013-08-10 13:38:48182 return PP_ERROR_FAILED;
[email protected]c77144722013-01-19 04:16:36183
184 state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_EXCLUSIVE);
[email protected]914a4ba92013-08-10 13:38:48185
186 // If the callback is blocking, perform the task on the calling thread.
187 if (callback->is_blocking()) {
[email protected]452fb142013-10-23 01:49:43188 int32_t result = PP_ERROR_FAILED;
[email protected]141bcc52014-01-27 21:36:00189 base::File::Info file_info;
[email protected]452fb142013-10-23 01:49:43190 // The plugin could release its reference to this instance when we release
191 // the proxy lock below.
192 scoped_refptr<FileIOResource> protect(this);
[email protected]914a4ba92013-08-10 13:38:48193 {
194 // Release the proxy lock while making a potentially slow file call.
195 ProxyAutoUnlock unlock;
[email protected]35b05b12014-06-03 00:01:03196 if (file_holder_->file()->GetInfo(&file_info))
[email protected]452fb142013-10-23 01:49:43197 result = PP_OK;
[email protected]914a4ba92013-08-10 13:38:48198 }
[email protected]452fb142013-10-23 01:49:43199 if (result == PP_OK) {
200 // This writes the file info into the plugin's PP_FileInfo struct.
[email protected]141bcc52014-01-27 21:36:00201 ppapi::FileInfoToPepperFileInfo(file_info,
202 file_system_type_,
203 info);
[email protected]452fb142013-10-23 01:49:43204 }
205 state_manager_.SetOperationFinished();
206 return result;
[email protected]914a4ba92013-08-10 13:38:48207 }
208
209 // For the non-blocking case, post a task to the file thread and add a
210 // completion task to write the result.
[email protected]35b05b12014-06-03 00:01:03211 scoped_refptr<QueryOp> query_op(new QueryOp(file_holder_));
[email protected]914a4ba92013-08-10 13:38:48212 base::PostTaskAndReplyWithResult(
Jan Wilken Dörrie1d33fc62020-01-23 10:20:47213 PpapiGlobals::Get()->GetFileTaskRunner(), FROM_HERE,
214 base::BindOnce(&FileIOResource::QueryOp::DoWork, query_op),
215 RunWhileLocked(base::BindOnce(&TrackedCallback::Run, callback)));
[email protected]914a4ba92013-08-10 13:38:48216 callback->set_completion_task(
217 Bind(&FileIOResource::OnQueryComplete, this, query_op, info));
218
[email protected]c77144722013-01-19 04:16:36219 return PP_OK_COMPLETIONPENDING;
220}
221
222int32_t FileIOResource::Touch(PP_Time last_access_time,
223 PP_Time last_modified_time,
224 scoped_refptr<TrackedCallback> callback) {
225 int32_t rv = state_manager_.CheckOperationState(
226 FileIOStateManager::OPERATION_EXCLUSIVE, true);
227 if (rv != PP_OK)
228 return rv;
229
[email protected]10c39222013-11-13 20:09:25230 Call<PpapiPluginMsg_FileIO_GeneralReply>(BROWSER,
[email protected]c77144722013-01-19 04:16:36231 PpapiHostMsg_FileIO_Touch(last_access_time, last_modified_time),
232 base::Bind(&FileIOResource::OnPluginMsgGeneralComplete, this,
233 callback));
234
235 state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_EXCLUSIVE);
236 return PP_OK_COMPLETIONPENDING;
237}
238
239int32_t FileIOResource::Read(int64_t offset,
240 char* buffer,
241 int32_t bytes_to_read,
242 scoped_refptr<TrackedCallback> callback) {
243 int32_t rv = state_manager_.CheckOperationState(
244 FileIOStateManager::OPERATION_READ, true);
245 if (rv != PP_OK)
246 return rv;
247
248 PP_ArrayOutput output_adapter;
249 output_adapter.GetDataBuffer = &DummyGetDataBuffer;
250 output_adapter.user_data = buffer;
[email protected]c77144722013-01-19 04:16:36251 return ReadValidated(offset, bytes_to_read, output_adapter, callback);
252}
253
254int32_t FileIOResource::ReadToArray(int64_t offset,
255 int32_t max_read_length,
256 PP_ArrayOutput* array_output,
257 scoped_refptr<TrackedCallback> callback) {
258 DCHECK(array_output);
259 int32_t rv = state_manager_.CheckOperationState(
260 FileIOStateManager::OPERATION_READ, true);
261 if (rv != PP_OK)
262 return rv;
263
[email protected]c77144722013-01-19 04:16:36264 return ReadValidated(offset, max_read_length, *array_output, callback);
265}
266
267int32_t FileIOResource::Write(int64_t offset,
268 const char* buffer,
269 int32_t bytes_to_write,
270 scoped_refptr<TrackedCallback> callback) {
[email protected]7a90b852013-12-28 17:54:27271 if (!buffer)
272 return PP_ERROR_FAILED;
[email protected]304875d2014-01-22 10:31:12273 if (offset < 0 || bytes_to_write < 0)
[email protected]7a90b852013-12-28 17:54:27274 return PP_ERROR_FAILED;
[email protected]35b05b12014-06-03 00:01:03275 if (!FileHolder::IsValid(file_holder_))
[email protected]7a90b852013-12-28 17:54:27276 return PP_ERROR_FAILED;
277
[email protected]c77144722013-01-19 04:16:36278 int32_t rv = state_manager_.CheckOperationState(
279 FileIOStateManager::OPERATION_WRITE, true);
280 if (rv != PP_OK)
281 return rv;
282
[email protected]c77144722013-01-19 04:16:36283 state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_WRITE);
[email protected]7a90b852013-12-28 17:54:27284
285 if (check_quota_) {
[email protected]304875d2014-01-22 10:31:12286 int64_t increase = 0;
287 uint64_t max_offset = 0;
288 bool append = (open_flags_ & PP_FILEOPENFLAG_APPEND) != 0;
289 if (append) {
290 increase = bytes_to_write;
291 } else {
292 uint64_t max_offset = offset + bytes_to_write;
avidd4e614352015-12-09 00:44:49293 if (max_offset >
294 static_cast<uint64_t>(std::numeric_limits<int64_t>::max())) {
[email protected]304875d2014-01-22 10:31:12295 return PP_ERROR_FAILED; // amount calculation would overflow.
avidd4e614352015-12-09 00:44:49296 }
[email protected]304875d2014-01-22 10:31:12297 increase = static_cast<int64_t>(max_offset) - max_written_offset_;
298 }
[email protected]7a90b852013-12-28 17:54:27299
[email protected]7a90b852013-12-28 17:54:27300 if (increase > 0) {
[email protected]6c644b7e2014-05-22 06:25:18301 // Request a quota reservation. This makes the Write asynchronous, so we
302 // must copy the plugin's buffer.
dchengced92242016-04-07 00:00:12303 std::unique_ptr<char[]> copy(new char[bytes_to_write]);
[email protected]6c644b7e2014-05-22 06:25:18304 memcpy(copy.get(), buffer, bytes_to_write);
[email protected]7a90b852013-12-28 17:54:27305 int64_t result =
306 file_system_resource_->AsPPB_FileSystem_API()->RequestQuota(
307 increase,
Jan Wilken Dörrie15647162020-04-20 10:09:58308 base::BindOnce(&FileIOResource::OnRequestWriteQuotaComplete, this,
309 offset, base::Passed(&copy), bytes_to_write,
310 callback));
[email protected]7a90b852013-12-28 17:54:27311 if (result == PP_OK_COMPLETIONPENDING)
312 return PP_OK_COMPLETIONPENDING;
313 DCHECK(result == increase);
[email protected]304875d2014-01-22 10:31:12314
315 if (append)
316 append_mode_write_amount_ += bytes_to_write;
317 else
318 max_written_offset_ = max_offset;
[email protected]7a90b852013-12-28 17:54:27319 }
320 }
321 return WriteValidated(offset, buffer, bytes_to_write, callback);
[email protected]c77144722013-01-19 04:16:36322}
323
324int32_t FileIOResource::SetLength(int64_t length,
325 scoped_refptr<TrackedCallback> callback) {
326 int32_t rv = state_manager_.CheckOperationState(
327 FileIOStateManager::OPERATION_EXCLUSIVE, true);
328 if (rv != PP_OK)
329 return rv;
[email protected]7a90b852013-12-28 17:54:27330 if (length < 0)
331 return PP_ERROR_FAILED;
[email protected]c77144722013-01-19 04:16:36332
[email protected]7a90b852013-12-28 17:54:27333 if (check_quota_) {
334 int64_t increase = length - max_written_offset_;
335 if (increase > 0) {
336 int32_t result =
337 file_system_resource_->AsPPB_FileSystem_API()->RequestQuota(
338 increase,
Jan Wilken Dörrie15647162020-04-20 10:09:58339 base::BindOnce(&FileIOResource::OnRequestSetLengthQuotaComplete,
340 this, length, callback));
[email protected]7a90b852013-12-28 17:54:27341 if (result == PP_OK_COMPLETIONPENDING) {
342 state_manager_.SetPendingOperation(
343 FileIOStateManager::OPERATION_EXCLUSIVE);
344 return PP_OK_COMPLETIONPENDING;
345 }
346 DCHECK(result == increase);
347 max_written_offset_ = length;
348 }
349 }
[email protected]c77144722013-01-19 04:16:36350
351 state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_EXCLUSIVE);
[email protected]7a90b852013-12-28 17:54:27352 SetLengthValidated(length, callback);
[email protected]c77144722013-01-19 04:16:36353 return PP_OK_COMPLETIONPENDING;
354}
355
356int32_t FileIOResource::Flush(scoped_refptr<TrackedCallback> callback) {
357 int32_t rv = state_manager_.CheckOperationState(
358 FileIOStateManager::OPERATION_EXCLUSIVE, true);
359 if (rv != PP_OK)
360 return rv;
361
[email protected]10c39222013-11-13 20:09:25362 Call<PpapiPluginMsg_FileIO_GeneralReply>(BROWSER,
[email protected]c77144722013-01-19 04:16:36363 PpapiHostMsg_FileIO_Flush(),
364 base::Bind(&FileIOResource::OnPluginMsgGeneralComplete, this,
365 callback));
366
367 state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_EXCLUSIVE);
368 return PP_OK_COMPLETIONPENDING;
369}
370
[email protected]7a90b852013-12-28 17:54:27371int64_t FileIOResource::GetMaxWrittenOffset() const {
372 return max_written_offset_;
373}
374
[email protected]304875d2014-01-22 10:31:12375int64_t FileIOResource::GetAppendModeWriteAmount() const {
376 return append_mode_write_amount_;
377}
378
[email protected]7a90b852013-12-28 17:54:27379void FileIOResource::SetMaxWrittenOffset(int64_t max_written_offset) {
380 max_written_offset_ = max_written_offset;
381}
382
[email protected]304875d2014-01-22 10:31:12383void FileIOResource::SetAppendModeWriteAmount(
384 int64_t append_mode_write_amount) {
385 append_mode_write_amount_ = append_mode_write_amount;
386}
387
[email protected]c77144722013-01-19 04:16:36388void FileIOResource::Close() {
[email protected]3dbfbe512013-12-27 22:53:00389 if (called_close_)
390 return;
391
392 called_close_ = true;
[email protected]7a90b852013-12-28 17:54:27393 if (check_quota_) {
394 check_quota_ = false;
395 file_system_resource_->AsPPB_FileSystem_API()->CloseQuotaFile(
396 pp_resource());
397 }
398
Daniel Cheng6d3ae972014-08-26 00:27:38399 if (file_holder_.get())
kylechar37594cb2019-11-15 16:41:17400 file_holder_.reset();
[email protected]3dbfbe512013-12-27 22:53:00401
[email protected]304875d2014-01-22 10:31:12402 Post(BROWSER, PpapiHostMsg_FileIO_Close(
[email protected]540d6af42014-01-28 21:19:03403 FileGrowth(max_written_offset_, append_mode_write_amount_)));
[email protected]c77144722013-01-19 04:16:36404}
405
[email protected]8f96cef2013-04-01 16:51:13406int32_t FileIOResource::RequestOSFileHandle(
407 PP_FileHandle* handle,
408 scoped_refptr<TrackedCallback> callback) {
409 int32_t rv = state_manager_.CheckOperationState(
410 FileIOStateManager::OPERATION_EXCLUSIVE, true);
411 if (rv != PP_OK)
412 return rv;
413
[email protected]10c39222013-11-13 20:09:25414 Call<PpapiPluginMsg_FileIO_RequestOSFileHandleReply>(BROWSER,
[email protected]8f96cef2013-04-01 16:51:13415 PpapiHostMsg_FileIO_RequestOSFileHandle(),
416 base::Bind(&FileIOResource::OnPluginMsgRequestOSFileHandleComplete, this,
417 callback, handle));
418
419 state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_EXCLUSIVE);
420 return PP_OK_COMPLETIONPENDING;
421}
422
[email protected]35b05b12014-06-03 00:01:03423FileIOResource::FileHolder::FileHolder(PP_FileHandle file_handle)
424 : file_(file_handle) {
[email protected]d35d3f42013-10-02 19:52:20425}
426
427// static
[email protected]35b05b12014-06-03 00:01:03428bool FileIOResource::FileHolder::IsValid(
429 const scoped_refptr<FileIOResource::FileHolder>& handle) {
Daniel Cheng6d3ae972014-08-26 00:27:38430 return handle.get() && handle->file_.IsValid();
[email protected]d35d3f42013-10-02 19:52:20431}
432
[email protected]35b05b12014-06-03 00:01:03433FileIOResource::FileHolder::~FileHolder() {
434 if (file_.IsValid()) {
[email protected]d35d3f42013-10-02 19:52:20435 base::TaskRunner* file_task_runner =
436 PpapiGlobals::Get()->GetFileTaskRunner();
437 file_task_runner->PostTask(FROM_HERE,
Jan Wilken Dörrie1494205b2020-03-26 09:32:53438 base::BindOnce(&DoClose, std::move(file_)));
[email protected]d35d3f42013-10-02 19:52:20439 }
440}
441
[email protected]d45f29b2013-08-09 04:18:06442int32_t FileIOResource::ReadValidated(int64_t offset,
443 int32_t bytes_to_read,
444 const PP_ArrayOutput& array_output,
445 scoped_refptr<TrackedCallback> callback) {
[email protected]914a4ba92013-08-10 13:38:48446 if (bytes_to_read < 0)
447 return PP_ERROR_FAILED;
[email protected]35b05b12014-06-03 00:01:03448 if (!FileHolder::IsValid(file_holder_))
[email protected]914a4ba92013-08-10 13:38:48449 return PP_ERROR_FAILED;
450
[email protected]d45f29b2013-08-09 04:18:06451 state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_READ);
452
[email protected]6f684412013-12-12 23:18:37453 bytes_to_read = std::min(bytes_to_read, kMaxReadWriteSize);
[email protected]914a4ba92013-08-10 13:38:48454 if (callback->is_blocking()) {
[email protected]452fb142013-10-23 01:49:43455 char* buffer = static_cast<char*>(
456 array_output.GetDataBuffer(array_output.user_data, bytes_to_read, 1));
457 int32_t result = PP_ERROR_FAILED;
458 // The plugin could release its reference to this instance when we release
459 // the proxy lock below.
460 scoped_refptr<FileIOResource> protect(this);
461 if (buffer) {
[email protected]914a4ba92013-08-10 13:38:48462 // Release the proxy lock while making a potentially slow file call.
463 ProxyAutoUnlock unlock;
[email protected]35b05b12014-06-03 00:01:03464 result = file_holder_->file()->Read(offset, buffer, bytes_to_read);
[email protected]452fb142013-10-23 01:49:43465 if (result < 0)
466 result = PP_ERROR_FAILED;
[email protected]d45f29b2013-08-09 04:18:06467 }
[email protected]452fb142013-10-23 01:49:43468 state_manager_.SetOperationFinished();
469 return result;
[email protected]d45f29b2013-08-09 04:18:06470 }
471
[email protected]914a4ba92013-08-10 13:38:48472 // For the non-blocking case, post a task to the file thread.
[email protected]452fb142013-10-23 01:49:43473 scoped_refptr<ReadOp> read_op(
[email protected]35b05b12014-06-03 00:01:03474 new ReadOp(file_holder_, offset, bytes_to_read));
[email protected]914a4ba92013-08-10 13:38:48475 base::PostTaskAndReplyWithResult(
Jan Wilken Dörrie1d33fc62020-01-23 10:20:47476 PpapiGlobals::Get()->GetFileTaskRunner(), FROM_HERE,
477 base::BindOnce(&FileIOResource::ReadOp::DoWork, read_op),
478 RunWhileLocked(base::BindOnce(&TrackedCallback::Run, callback)));
[email protected]914a4ba92013-08-10 13:38:48479 callback->set_completion_task(
480 Bind(&FileIOResource::OnReadComplete, this, read_op, array_output));
481
[email protected]d45f29b2013-08-09 04:18:06482 return PP_OK_COMPLETIONPENDING;
483}
484
[email protected]7a90b852013-12-28 17:54:27485int32_t FileIOResource::WriteValidated(
486 int64_t offset,
487 const char* buffer,
488 int32_t bytes_to_write,
489 scoped_refptr<TrackedCallback> callback) {
490 bool append = (open_flags_ & PP_FILEOPENFLAG_APPEND) != 0;
491 if (callback->is_blocking()) {
492 int32_t result;
493 {
494 // Release the proxy lock while making a potentially slow file call.
495 ProxyAutoUnlock unlock;
496 if (append) {
[email protected]35b05b12014-06-03 00:01:03497 result = file_holder_->file()->WriteAtCurrentPos(buffer,
498 bytes_to_write);
[email protected]7a90b852013-12-28 17:54:27499 } else {
[email protected]35b05b12014-06-03 00:01:03500 result = file_holder_->file()->Write(offset, buffer, bytes_to_write);
[email protected]7a90b852013-12-28 17:54:27501 }
502 }
503 if (result < 0)
504 result = PP_ERROR_FAILED;
505
506 state_manager_.SetOperationFinished();
507 return result;
508 }
509
[email protected]6c644b7e2014-05-22 06:25:18510 // For the non-blocking case, post a task to the file thread. We must copy the
511 // plugin's buffer at this point.
dchengced92242016-04-07 00:00:12512 std::unique_ptr<char[]> copy(new char[bytes_to_write]);
[email protected]6c644b7e2014-05-22 06:25:18513 memcpy(copy.get(), buffer, bytes_to_write);
dchengd2b9f612015-12-18 19:08:51514 scoped_refptr<WriteOp> write_op(new WriteOp(
515 file_holder_, offset, std::move(copy), bytes_to_write, append));
[email protected]7a90b852013-12-28 17:54:27516 base::PostTaskAndReplyWithResult(
Jan Wilken Dörrie1d33fc62020-01-23 10:20:47517 PpapiGlobals::Get()->GetFileTaskRunner(), FROM_HERE,
518 base::BindOnce(&FileIOResource::WriteOp::DoWork, write_op),
519 RunWhileLocked(base::BindOnce(&TrackedCallback::Run, callback)));
[email protected]6c644b7e2014-05-22 06:25:18520 callback->set_completion_task(Bind(&FileIOResource::OnWriteComplete, this));
[email protected]7a90b852013-12-28 17:54:27521
522 return PP_OK_COMPLETIONPENDING;
523}
524
525void FileIOResource::SetLengthValidated(
526 int64_t length,
527 scoped_refptr<TrackedCallback> callback) {
528 Call<PpapiPluginMsg_FileIO_GeneralReply>(BROWSER,
529 PpapiHostMsg_FileIO_SetLength(length),
530 base::Bind(&FileIOResource::OnPluginMsgGeneralComplete, this,
531 callback));
532
[email protected]304875d2014-01-22 10:31:12533 // On the browser side we grow |max_written_offset_| monotonically, due to the
534 // unpredictable ordering of plugin side Write and SetLength calls. Match that
535 // behavior here.
536 if (max_written_offset_ < length)
537 max_written_offset_ = length;
[email protected]7a90b852013-12-28 17:54:27538}
539
[email protected]914a4ba92013-08-10 13:38:48540int32_t FileIOResource::OnQueryComplete(scoped_refptr<QueryOp> query_op,
541 PP_FileInfo* info,
542 int32_t result) {
543 DCHECK(state_manager_.get_pending_operation() ==
544 FileIOStateManager::OPERATION_EXCLUSIVE);
545
546 if (result == PP_OK) {
547 // This writes the file info into the plugin's PP_FileInfo struct.
[email protected]141bcc52014-01-27 21:36:00548 ppapi::FileInfoToPepperFileInfo(query_op->file_info(),
549 file_system_type_,
550 info);
[email protected]914a4ba92013-08-10 13:38:48551 }
552 state_manager_.SetOperationFinished();
553 return result;
554}
555
556int32_t FileIOResource::OnReadComplete(scoped_refptr<ReadOp> read_op,
557 PP_ArrayOutput array_output,
558 int32_t result) {
559 DCHECK(state_manager_.get_pending_operation() ==
560 FileIOStateManager::OPERATION_READ);
561 if (result >= 0) {
562 ArrayWriter output;
563 output.set_pp_array_output(array_output);
564 if (output.is_valid())
565 output.StoreArray(read_op->buffer(), result);
566 else
567 result = PP_ERROR_FAILED;
568 } else {
569 // The read operation failed.
570 result = PP_ERROR_FAILED;
571 }
572 state_manager_.SetOperationFinished();
573 return result;
574}
575
[email protected]7a90b852013-12-28 17:54:27576void FileIOResource::OnRequestWriteQuotaComplete(
577 int64_t offset,
dchengced92242016-04-07 00:00:12578 std::unique_ptr<char[]> buffer,
[email protected]7a90b852013-12-28 17:54:27579 int32_t bytes_to_write,
580 scoped_refptr<TrackedCallback> callback,
581 int64_t granted) {
582 DCHECK(granted >= 0);
583 if (granted == 0) {
584 callback->Run(PP_ERROR_NOQUOTA);
585 return;
586 }
[email protected]304875d2014-01-22 10:31:12587 if (open_flags_ & PP_FILEOPENFLAG_APPEND) {
588 DCHECK_LE(bytes_to_write, granted);
589 append_mode_write_amount_ += bytes_to_write;
590 } else {
591 DCHECK_LE(offset + bytes_to_write - max_written_offset_, granted);
592
593 int64_t max_offset = offset + bytes_to_write;
594 if (max_written_offset_ < max_offset)
595 max_written_offset_ = max_offset;
596 }
597
[email protected]6c644b7e2014-05-22 06:25:18598 if (callback->is_blocking()) {
599 int32_t result =
600 WriteValidated(offset, buffer.get(), bytes_to_write, callback);
601 DCHECK(result != PP_OK_COMPLETIONPENDING);
[email protected]7a90b852013-12-28 17:54:27602 callback->Run(result);
[email protected]6c644b7e2014-05-22 06:25:18603 } else {
604 bool append = (open_flags_ & PP_FILEOPENFLAG_APPEND) != 0;
605 scoped_refptr<WriteOp> write_op(new WriteOp(
dchengd2b9f612015-12-18 19:08:51606 file_holder_, offset, std::move(buffer), bytes_to_write, append));
[email protected]6c644b7e2014-05-22 06:25:18607 base::PostTaskAndReplyWithResult(
Jan Wilken Dörrie1d33fc62020-01-23 10:20:47608 PpapiGlobals::Get()->GetFileTaskRunner(), FROM_HERE,
609 base::BindOnce(&FileIOResource::WriteOp::DoWork, write_op),
610 RunWhileLocked(base::BindOnce(&TrackedCallback::Run, callback)));
[email protected]6c644b7e2014-05-22 06:25:18611 callback->set_completion_task(Bind(&FileIOResource::OnWriteComplete, this));
612 }
[email protected]7a90b852013-12-28 17:54:27613}
614
615void FileIOResource::OnRequestSetLengthQuotaComplete(
616 int64_t length,
617 scoped_refptr<TrackedCallback> callback,
618 int64_t granted) {
619 DCHECK(granted >= 0);
620 if (granted == 0) {
621 callback->Run(PP_ERROR_NOQUOTA);
622 return;
623 }
624
[email protected]304875d2014-01-22 10:31:12625 DCHECK_LE(length - max_written_offset_, granted);
626 if (max_written_offset_ < length)
627 max_written_offset_ = length;
[email protected]7a90b852013-12-28 17:54:27628 SetLengthValidated(length, callback);
629}
630
[email protected]6c644b7e2014-05-22 06:25:18631int32_t FileIOResource::OnWriteComplete(int32_t result) {
[email protected]7a90b852013-12-28 17:54:27632 DCHECK(state_manager_.get_pending_operation() ==
633 FileIOStateManager::OPERATION_WRITE);
634 // |result| is the return value of WritePlatformFile; -1 indicates failure.
635 if (result < 0)
636 result = PP_ERROR_FAILED;
637
638 state_manager_.SetOperationFinished();
639 return result;
640}
641
[email protected]c77144722013-01-19 04:16:36642void FileIOResource::OnPluginMsgGeneralComplete(
643 scoped_refptr<TrackedCallback> callback,
644 const ResourceMessageReplyParams& params) {
645 DCHECK(state_manager_.get_pending_operation() ==
646 FileIOStateManager::OPERATION_EXCLUSIVE ||
647 state_manager_.get_pending_operation() ==
648 FileIOStateManager::OPERATION_WRITE);
[email protected]d45f29b2013-08-09 04:18:06649 // End this operation now, so the user's callback can execute another FileIO
650 // operation, assuming there are no other pending operations.
[email protected]c77144722013-01-19 04:16:36651 state_manager_.SetOperationFinished();
652 callback->Run(params.result());
653}
654
655void FileIOResource::OnPluginMsgOpenFileComplete(
656 scoped_refptr<TrackedCallback> callback,
[email protected]7a90b852013-12-28 17:54:27657 const ResourceMessageReplyParams& params,
658 PP_Resource quota_file_system,
659 int64_t max_written_offset) {
[email protected]c77144722013-01-19 04:16:36660 DCHECK(state_manager_.get_pending_operation() ==
661 FileIOStateManager::OPERATION_EXCLUSIVE);
[email protected]c6420f082013-09-18 22:42:41662
663 // Release the FileRef resource.
kylechar37594cb2019-11-15 16:41:17664 file_ref_.reset();
[email protected]7a90b852013-12-28 17:54:27665 int32_t result = params.result();
666 if (result == PP_OK) {
[email protected]c77144722013-01-19 04:16:36667 state_manager_.SetOpenSucceed();
[email protected]d45f29b2013-08-09 04:18:06668
[email protected]7a90b852013-12-28 17:54:27669 if (quota_file_system) {
670 DCHECK(quota_file_system == file_system_resource_->pp_resource());
671 check_quota_ = true;
672 max_written_offset_ = max_written_offset;
673 file_system_resource_->AsPPB_FileSystem_API()->OpenQuotaFile(
674 pp_resource());
675 }
676
677 IPC::PlatformFileForTransit transit_file;
678 if (params.TakeFileHandleAtIndex(0, &transit_file)) {
[email protected]35b05b12014-06-03 00:01:03679 file_holder_ = new FileHolder(
[email protected]7a90b852013-12-28 17:54:27680 IPC::PlatformFileForTransitToPlatformFile(transit_file));
681 }
[email protected]d35d3f42013-10-02 19:52:20682 }
[email protected]d45f29b2013-08-09 04:18:06683 // End this operation now, so the user's callback can execute another FileIO
684 // operation, assuming there are no other pending operations.
[email protected]23e78de2013-07-26 20:28:47685 state_manager_.SetOperationFinished();
[email protected]d45f29b2013-08-09 04:18:06686 callback->Run(result);
[email protected]23e78de2013-07-26 20:28:47687}
688
[email protected]8f96cef2013-04-01 16:51:13689void FileIOResource::OnPluginMsgRequestOSFileHandleComplete(
690 scoped_refptr<TrackedCallback> callback,
691 PP_FileHandle* output_handle,
692 const ResourceMessageReplyParams& params) {
693 DCHECK(state_manager_.get_pending_operation() ==
694 FileIOStateManager::OPERATION_EXCLUSIVE);
695
696 if (!TrackedCallback::IsPending(callback)) {
697 state_manager_.SetOperationFinished();
698 return;
699 }
700
701 int32_t result = params.result();
702 IPC::PlatformFileForTransit transit_file;
703 if (!params.TakeFileHandleAtIndex(0, &transit_file))
704 result = PP_ERROR_FAILED;
705 *output_handle = IPC::PlatformFileForTransitToPlatformFile(transit_file);
706
[email protected]d45f29b2013-08-09 04:18:06707 // End this operation now, so the user's callback can execute another FileIO
708 // operation, assuming there are no other pending operations.
[email protected]8f96cef2013-04-01 16:51:13709 state_manager_.SetOperationFinished();
710 callback->Run(result);
711}
712
[email protected]c77144722013-01-19 04:16:36713} // namespace proxy
714} // namespace ppapi