diff options
Diffstat (limited to 'ppapi/proxy/file_io_resource.cc')
-rw-r--r-- | ppapi/proxy/file_io_resource.cc | 231 |
1 files changed, 209 insertions, 22 deletions
diff --git a/ppapi/proxy/file_io_resource.cc b/ppapi/proxy/file_io_resource.cc index ad07187..e86c321 100644 --- a/ppapi/proxy/file_io_resource.cc +++ b/ppapi/proxy/file_io_resource.cc @@ -80,9 +80,39 @@ int32_t FileIOResource::ReadOp::DoWork() { file_handle_->raw_handle(), offset_, buffer_.get(), bytes_to_read_); } +FileIOResource::WriteOp::WriteOp(scoped_refptr<FileHandleHolder> file_handle, + int64_t offset, + const char* buffer, + int32_t bytes_to_write, + bool append) + : file_handle_(file_handle), + offset_(offset), + buffer_(buffer), + bytes_to_write_(bytes_to_write), + append_(append) { +} + +FileIOResource::WriteOp::~WriteOp() { +} + +int32_t FileIOResource::WriteOp::DoWork() { + // We can't just call WritePlatformFile in append mode, since NaCl doesn't + // implement fcntl, causing the function to call pwrite, which is incorrect. + if (append_) { + return base::WritePlatformFileAtCurrentPos( + file_handle_->raw_handle(), buffer_, bytes_to_write_); + } else { + return base::WritePlatformFile( + file_handle_->raw_handle(), offset_, buffer_, bytes_to_write_); + } +} + FileIOResource::FileIOResource(Connection connection, PP_Instance instance) : PluginResource(connection, instance), file_system_type_(PP_FILESYSTEMTYPE_INVALID), + open_flags_(0), + max_written_offset_(0), + check_quota_(false), called_close_(false) { SendCreate(BROWSER, PpapiHostMsg_FileIO_Create()); } @@ -113,6 +143,7 @@ int32_t FileIOResource::Open(PP_Resource file_ref, if (rv != PP_OK) return rv; + open_flags_ = open_flags; file_system_type_ = create_info.file_system_type; if (create_info.file_system_plugin_resource) { @@ -239,22 +270,42 @@ int32_t FileIOResource::Write(int64_t offset, const char* buffer, int32_t bytes_to_write, scoped_refptr<TrackedCallback> callback) { + if (!buffer) + return PP_ERROR_FAILED; + if (bytes_to_write < 0) + return PP_ERROR_FAILED; + if (!FileHandleHolder::IsValid(file_handle_)) + return PP_ERROR_FAILED; + int32_t rv = state_manager_.CheckOperationState( FileIOStateManager::OPERATION_WRITE, true); if (rv != PP_OK) return rv; - // TODO(brettw) it would be nice to use a shared memory buffer for large - // writes rather than having to copy to a string (which will involve a number - // of extra copies to serialize over IPC). - bytes_to_write = std::min(bytes_to_write, kMaxReadWriteSize); - Call<PpapiPluginMsg_FileIO_GeneralReply>(BROWSER, - PpapiHostMsg_FileIO_Write(offset, std::string(buffer, bytes_to_write)), - base::Bind(&FileIOResource::OnPluginMsgGeneralComplete, this, - callback)); - state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_WRITE); - return PP_OK_COMPLETIONPENDING; + + if (check_quota_) { + int64_t actual_offset = + (open_flags_ & PP_FILEOPENFLAG_APPEND) ? max_written_offset_ : offset; + + uint64_t max_offset = actual_offset + bytes_to_write; + if (max_offset > static_cast<uint64_t>(std::numeric_limits<int64_t>::max())) + return PP_ERROR_FAILED; // amount calculation would overflow. + int64_t increase = static_cast<int64_t>(max_offset) - max_written_offset_; + if (increase > 0) { + int64_t result = + file_system_resource_->AsPPB_FileSystem_API()->RequestQuota( + increase, + base::Bind(&FileIOResource::OnRequestWriteQuotaComplete, + this, + offset, buffer, bytes_to_write, callback)); + if (result == PP_OK_COMPLETIONPENDING) + return PP_OK_COMPLETIONPENDING; + DCHECK(result == increase); + max_written_offset_ = max_offset; + } + } + return WriteValidated(offset, buffer, bytes_to_write, callback); } int32_t FileIOResource::SetLength(int64_t length, @@ -263,13 +314,30 @@ int32_t FileIOResource::SetLength(int64_t length, FileIOStateManager::OPERATION_EXCLUSIVE, true); if (rv != PP_OK) return rv; + if (length < 0) + return PP_ERROR_FAILED; - Call<PpapiPluginMsg_FileIO_GeneralReply>(BROWSER, - PpapiHostMsg_FileIO_SetLength(length), - base::Bind(&FileIOResource::OnPluginMsgGeneralComplete, this, - callback)); + if (check_quota_) { + int64_t increase = length - max_written_offset_; + if (increase > 0) { + int32_t result = + file_system_resource_->AsPPB_FileSystem_API()->RequestQuota( + increase, + base::Bind(&FileIOResource::OnRequestSetLengthQuotaComplete, + this, + length, callback)); + if (result == PP_OK_COMPLETIONPENDING) { + state_manager_.SetPendingOperation( + FileIOStateManager::OPERATION_EXCLUSIVE); + return PP_OK_COMPLETIONPENDING; + } + DCHECK(result == increase); + max_written_offset_ = length; + } + } state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_EXCLUSIVE); + SetLengthValidated(length, callback); return PP_OK_COMPLETIONPENDING; } @@ -288,15 +356,29 @@ int32_t FileIOResource::Flush(scoped_refptr<TrackedCallback> callback) { return PP_OK_COMPLETIONPENDING; } +int64_t FileIOResource::GetMaxWrittenOffset() const { + return max_written_offset_; +} + +void FileIOResource::SetMaxWrittenOffset(int64_t max_written_offset) { + max_written_offset_ = max_written_offset; +} + void FileIOResource::Close() { if (called_close_) return; called_close_ = true; + if (check_quota_) { + check_quota_ = false; + file_system_resource_->AsPPB_FileSystem_API()->CloseQuotaFile( + pp_resource()); + } + if (file_handle_) file_handle_ = NULL; - Post(BROWSER, PpapiHostMsg_FileIO_Close()); + Post(BROWSER, PpapiHostMsg_FileIO_Close(max_written_offset_)); } int32_t FileIOResource::RequestOSFileHandle( @@ -380,6 +462,57 @@ int32_t FileIOResource::ReadValidated(int64_t offset, return PP_OK_COMPLETIONPENDING; } +int32_t FileIOResource::WriteValidated( + int64_t offset, + const char* buffer, + int32_t bytes_to_write, + scoped_refptr<TrackedCallback> callback) { + bool append = (open_flags_ & PP_FILEOPENFLAG_APPEND) != 0; + if (callback->is_blocking()) { + int32_t result; + { + // Release the proxy lock while making a potentially slow file call. + ProxyAutoUnlock unlock; + if (append) { + result = base::WritePlatformFileAtCurrentPos( + file_handle_->raw_handle(), buffer, bytes_to_write); + } else { + result = base::WritePlatformFile( + file_handle_->raw_handle(), offset, buffer, bytes_to_write); + } + } + if (result < 0) + result = PP_ERROR_FAILED; + + state_manager_.SetOperationFinished(); + return result; + } + + // For the non-blocking case, post a task to the file thread. + scoped_refptr<WriteOp> write_op( + new WriteOp(file_handle_, offset, buffer, bytes_to_write, append)); + base::PostTaskAndReplyWithResult( + PpapiGlobals::Get()->GetFileTaskRunner(), + FROM_HERE, + Bind(&FileIOResource::WriteOp::DoWork, write_op), + RunWhileLocked(Bind(&TrackedCallback::Run, callback))); + callback->set_completion_task( + Bind(&FileIOResource::OnWriteComplete, this, write_op)); + + return PP_OK_COMPLETIONPENDING; +} + +void FileIOResource::SetLengthValidated( + int64_t length, + scoped_refptr<TrackedCallback> callback) { + Call<PpapiPluginMsg_FileIO_GeneralReply>(BROWSER, + PpapiHostMsg_FileIO_SetLength(length), + base::Bind(&FileIOResource::OnPluginMsgGeneralComplete, this, + callback)); + + max_written_offset_ = length; +} + int32_t FileIOResource::OnQueryComplete(scoped_refptr<QueryOp> query_op, PP_FileInfo* info, int32_t result) { @@ -416,6 +549,49 @@ int32_t FileIOResource::OnReadComplete(scoped_refptr<ReadOp> read_op, return result; } +void FileIOResource::OnRequestWriteQuotaComplete( + int64_t offset, + const char* buffer, + int32_t bytes_to_write, + scoped_refptr<TrackedCallback> callback, + int64_t granted) { + DCHECK(granted >= 0); + if (granted == 0) { + callback->Run(PP_ERROR_NOQUOTA); + return; + } + max_written_offset_ += granted; + int32_t result = WriteValidated(offset, buffer, bytes_to_write, callback); + if (result != PP_OK_COMPLETIONPENDING) + callback->Run(result); +} + +void FileIOResource::OnRequestSetLengthQuotaComplete( + int64_t length, + scoped_refptr<TrackedCallback> callback, + int64_t granted) { + DCHECK(granted >= 0); + if (granted == 0) { + callback->Run(PP_ERROR_NOQUOTA); + return; + } + + max_written_offset_ = length; + SetLengthValidated(length, callback); +} + +int32_t FileIOResource::OnWriteComplete(scoped_refptr<WriteOp> write_op, + int32_t result) { + DCHECK(state_manager_.get_pending_operation() == + FileIOStateManager::OPERATION_WRITE); + // |result| is the return value of WritePlatformFile; -1 indicates failure. + if (result < 0) + result = PP_ERROR_FAILED; + + state_manager_.SetOperationFinished(); + return result; +} + void FileIOResource::OnPluginMsgGeneralComplete( scoped_refptr<TrackedCallback> callback, const ResourceMessageReplyParams& params) { @@ -431,20 +607,31 @@ void FileIOResource::OnPluginMsgGeneralComplete( void FileIOResource::OnPluginMsgOpenFileComplete( scoped_refptr<TrackedCallback> callback, - const ResourceMessageReplyParams& params) { + const ResourceMessageReplyParams& params, + PP_Resource quota_file_system, + int64_t max_written_offset) { DCHECK(state_manager_.get_pending_operation() == FileIOStateManager::OPERATION_EXCLUSIVE); // Release the FileRef resource. file_ref_ = NULL; - if (params.result() == PP_OK) + int32_t result = params.result(); + if (result == PP_OK) { state_manager_.SetOpenSucceed(); - int32_t result = params.result(); - IPC::PlatformFileForTransit transit_file; - if ((result == PP_OK) && params.TakeFileHandleAtIndex(0, &transit_file)) { - file_handle_ = new FileHandleHolder( - IPC::PlatformFileForTransitToPlatformFile(transit_file)); + if (quota_file_system) { + DCHECK(quota_file_system == file_system_resource_->pp_resource()); + check_quota_ = true; + max_written_offset_ = max_written_offset; + file_system_resource_->AsPPB_FileSystem_API()->OpenQuotaFile( + pp_resource()); + } + + IPC::PlatformFileForTransit transit_file; + if (params.TakeFileHandleAtIndex(0, &transit_file)) { + file_handle_ = new FileHandleHolder( + IPC::PlatformFileForTransitToPlatformFile(transit_file)); + } } // End this operation now, so the user's callback can execute another FileIO // operation, assuming there are no other pending operations. |