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