file_io_resource.cc revision f2477e01787aa58f445919b809d89e252beef54f
1726140821f96e3472a8eccef0c67c0b5ad65a1d9Chris Lattner// Copyright (c) 2012 The Chromium Authors. All rights reserved. 2856ba76200ec2302f2fe500bc507f426c7d566c8John Criswell// Use of this source code is governed by a BSD-style license that can be 3856ba76200ec2302f2fe500bc507f426c7d566c8John Criswell// found in the LICENSE file. 4856ba76200ec2302f2fe500bc507f426c7d566c8John Criswell 5856ba76200ec2302f2fe500bc507f426c7d566c8John Criswell#include "ppapi/proxy/file_io_resource.h" 6856ba76200ec2302f2fe500bc507f426c7d566c8John Criswell 7856ba76200ec2302f2fe500bc507f426c7d566c8John Criswell#include "base/bind.h" 8856ba76200ec2302f2fe500bc507f426c7d566c8John Criswell#include "base/task_runner_util.h" 9726140821f96e3472a8eccef0c67c0b5ad65a1d9Chris Lattner#include "ipc/ipc_message.h" 103501feab811c86c9659248a4875fc31a3165f84dChris Lattner#include "ppapi/c/pp_errors.h" 11726140821f96e3472a8eccef0c67c0b5ad65a1d9Chris Lattner#include "ppapi/proxy/ppapi_messages.h" 12726140821f96e3472a8eccef0c67c0b5ad65a1d9Chris Lattner#include "ppapi/shared_impl/array_writer.h" 13726140821f96e3472a8eccef0c67c0b5ad65a1d9Chris Lattner#include "ppapi/shared_impl/file_ref_create_info.h" 14726140821f96e3472a8eccef0c67c0b5ad65a1d9Chris Lattner#include "ppapi/shared_impl/file_system_util.h" 15726140821f96e3472a8eccef0c67c0b5ad65a1d9Chris Lattner#include "ppapi/shared_impl/file_type_conversion.h" 16726140821f96e3472a8eccef0c67c0b5ad65a1d9Chris Lattner#include "ppapi/shared_impl/ppapi_globals.h" 173501feab811c86c9659248a4875fc31a3165f84dChris Lattner#include "ppapi/shared_impl/proxy_lock.h" 18726140821f96e3472a8eccef0c67c0b5ad65a1d9Chris Lattner#include "ppapi/shared_impl/resource_tracker.h" 19726140821f96e3472a8eccef0c67c0b5ad65a1d9Chris Lattner#include "ppapi/thunk/enter.h" 20d0fde30ce850b78371fd1386338350591f9ff494Brian Gaeke#include "ppapi/thunk/ppb_file_ref_api.h" 21d0fde30ce850b78371fd1386338350591f9ff494Brian Gaeke 229d17740295838f94120646ef619b2e187f2d71bdChris Lattnerusing ppapi::thunk::EnterResourceNoLock; 239d17740295838f94120646ef619b2e187f2d71bdChris Lattnerusing ppapi::thunk::PPB_FileIO_API; 249d17740295838f94120646ef619b2e187f2d71bdChris Lattnerusing ppapi::thunk::PPB_FileRef_API; 259d17740295838f94120646ef619b2e187f2d71bdChris Lattner 269d17740295838f94120646ef619b2e187f2d71bdChris Lattnernamespace { 276aab9cf65cd1e96f9d0fa99f8453da454648bba1Chris Lattner 286aab9cf65cd1e96f9d0fa99f8453da454648bba1Chris Lattner// We must allocate a buffer sized according to the request of the plugin. To 296aab9cf65cd1e96f9d0fa99f8453da454648bba1Chris Lattner// reduce the chance of out-of-memory errors, we cap the read size to 32MB. 306aab9cf65cd1e96f9d0fa99f8453da454648bba1Chris Lattner// This is OK since the API specifies that it may perform a partial read. 316aab9cf65cd1e96f9d0fa99f8453da454648bba1Chris Lattnerstatic const int32_t kMaxReadSize = 32 * 1024 * 1024; // 32MB 324c299f5da1013cd36563a82f188c731b2758074dChris Lattner 334c299f5da1013cd36563a82f188c731b2758074dChris Lattner// An adapter to let Read() share the same implementation with ReadToArray(). 344c299f5da1013cd36563a82f188c731b2758074dChris Lattnervoid* DummyGetDataBuffer(void* user_data, uint32_t count, uint32_t size) { 354c299f5da1013cd36563a82f188c731b2758074dChris Lattner return user_data; 364c299f5da1013cd36563a82f188c731b2758074dChris Lattner} 376aab9cf65cd1e96f9d0fa99f8453da454648bba1Chris Lattner 386aab9cf65cd1e96f9d0fa99f8453da454648bba1Chris Lattner// File thread task to close the file handle. 394c299f5da1013cd36563a82f188c731b2758074dChris Lattnervoid DoClose(base::PlatformFile file) { 406aab9cf65cd1e96f9d0fa99f8453da454648bba1Chris Lattner base::ClosePlatformFile(file); 416aab9cf65cd1e96f9d0fa99f8453da454648bba1Chris Lattner} 426aab9cf65cd1e96f9d0fa99f8453da454648bba1Chris Lattner 434c299f5da1013cd36563a82f188c731b2758074dChris Lattner} // namespace 446aab9cf65cd1e96f9d0fa99f8453da454648bba1Chris Lattner 456aab9cf65cd1e96f9d0fa99f8453da454648bba1Chris Lattnernamespace ppapi { 466aab9cf65cd1e96f9d0fa99f8453da454648bba1Chris Lattnernamespace proxy { 476aab9cf65cd1e96f9d0fa99f8453da454648bba1Chris Lattner 484c299f5da1013cd36563a82f188c731b2758074dChris LattnerFileIOResource::QueryOp::QueryOp(scoped_refptr<FileHandleHolder> file_handle) 496aab9cf65cd1e96f9d0fa99f8453da454648bba1Chris Lattner : file_handle_(file_handle) { 506aab9cf65cd1e96f9d0fa99f8453da454648bba1Chris Lattner DCHECK(file_handle_); 516aab9cf65cd1e96f9d0fa99f8453da454648bba1Chris Lattner} 526aab9cf65cd1e96f9d0fa99f8453da454648bba1Chris Lattner 534c299f5da1013cd36563a82f188c731b2758074dChris LattnerFileIOResource::QueryOp::~QueryOp() { 546aab9cf65cd1e96f9d0fa99f8453da454648bba1Chris Lattner} 556aab9cf65cd1e96f9d0fa99f8453da454648bba1Chris Lattner 566aab9cf65cd1e96f9d0fa99f8453da454648bba1Chris Lattnerint32_t FileIOResource::QueryOp::DoWork() { 576aab9cf65cd1e96f9d0fa99f8453da454648bba1Chris Lattner return base::GetPlatformFileInfo(file_handle_->raw_handle(), &file_info_) ? 584c299f5da1013cd36563a82f188c731b2758074dChris Lattner PP_OK : PP_ERROR_FAILED; 596aab9cf65cd1e96f9d0fa99f8453da454648bba1Chris Lattner} 606aab9cf65cd1e96f9d0fa99f8453da454648bba1Chris Lattner 616aab9cf65cd1e96f9d0fa99f8453da454648bba1Chris LattnerFileIOResource::ReadOp::ReadOp(scoped_refptr<FileHandleHolder> file_handle, 626aab9cf65cd1e96f9d0fa99f8453da454648bba1Chris Lattner int64_t offset, 634c299f5da1013cd36563a82f188c731b2758074dChris Lattner int32_t bytes_to_read) 646aab9cf65cd1e96f9d0fa99f8453da454648bba1Chris Lattner : file_handle_(file_handle), 6585b39f229f3146e57d059f1c774400e4bde23987Chris Lattner offset_(offset), 6685b39f229f3146e57d059f1c774400e4bde23987Chris Lattner bytes_to_read_(bytes_to_read) { 6785b39f229f3146e57d059f1c774400e4bde23987Chris Lattner DCHECK(file_handle_); 6885b39f229f3146e57d059f1c774400e4bde23987Chris Lattner} 6985b39f229f3146e57d059f1c774400e4bde23987Chris Lattner 7085b39f229f3146e57d059f1c774400e4bde23987Chris LattnerFileIOResource::ReadOp::~ReadOp() { 7185b39f229f3146e57d059f1c774400e4bde23987Chris Lattner} 7285b39f229f3146e57d059f1c774400e4bde23987Chris Lattner 7385b39f229f3146e57d059f1c774400e4bde23987Chris Lattnerint32_t FileIOResource::ReadOp::DoWork() { 7485b39f229f3146e57d059f1c774400e4bde23987Chris Lattner DCHECK(!buffer_.get()); 7585b39f229f3146e57d059f1c774400e4bde23987Chris Lattner buffer_.reset(new char[bytes_to_read_]); 7685b39f229f3146e57d059f1c774400e4bde23987Chris Lattner return base::ReadPlatformFile( 776aab9cf65cd1e96f9d0fa99f8453da454648bba1Chris Lattner file_handle_->raw_handle(), offset_, buffer_.get(), bytes_to_read_); 7885b39f229f3146e57d059f1c774400e4bde23987Chris Lattner} 796aab9cf65cd1e96f9d0fa99f8453da454648bba1Chris Lattner 806aab9cf65cd1e96f9d0fa99f8453da454648bba1Chris LattnerFileIOResource::FileIOResource(Connection connection, PP_Instance instance) 816aab9cf65cd1e96f9d0fa99f8453da454648bba1Chris Lattner : PluginResource(connection, instance), 826aab9cf65cd1e96f9d0fa99f8453da454648bba1Chris Lattner file_system_type_(PP_FILESYSTEMTYPE_INVALID) { 8311e53e3c384e9e25f53a0aec3acf0a725efafeabChris Lattner SendCreate(BROWSER, PpapiHostMsg_FileIO_Create()); 8411e53e3c384e9e25f53a0aec3acf0a725efafeabChris Lattner} 8511e53e3c384e9e25f53a0aec3acf0a725efafeabChris Lattner 862959b6ec49be09096cf0a5e7504d2a1ec15ef2b3Chris LattnerFileIOResource::~FileIOResource() { 874c299f5da1013cd36563a82f188c731b2758074dChris Lattner} 884c299f5da1013cd36563a82f188c731b2758074dChris Lattner 894c299f5da1013cd36563a82f188c731b2758074dChris LattnerPPB_FileIO_API* FileIOResource::AsPPB_FileIO_API() { 904c299f5da1013cd36563a82f188c731b2758074dChris Lattner return this; 914c299f5da1013cd36563a82f188c731b2758074dChris Lattner} 924c299f5da1013cd36563a82f188c731b2758074dChris Lattner 932959b6ec49be09096cf0a5e7504d2a1ec15ef2b3Chris Lattnerint32_t FileIOResource::Open(PP_Resource file_ref, 942959b6ec49be09096cf0a5e7504d2a1ec15ef2b3Chris Lattner int32_t open_flags, 954c299f5da1013cd36563a82f188c731b2758074dChris Lattner scoped_refptr<TrackedCallback> callback) { 964c299f5da1013cd36563a82f188c731b2758074dChris Lattner EnterResourceNoLock<PPB_FileRef_API> enter(file_ref, true); 974c299f5da1013cd36563a82f188c731b2758074dChris Lattner if (enter.failed()) 982959b6ec49be09096cf0a5e7504d2a1ec15ef2b3Chris Lattner return PP_ERROR_BADRESOURCE; 994c299f5da1013cd36563a82f188c731b2758074dChris Lattner 1004c299f5da1013cd36563a82f188c731b2758074dChris Lattner PPB_FileRef_API* file_ref_api = enter.object(); 1014c299f5da1013cd36563a82f188c731b2758074dChris Lattner const FileRefCreateInfo& create_info = file_ref_api->GetCreateInfo(); 1022959b6ec49be09096cf0a5e7504d2a1ec15ef2b3Chris Lattner if (!FileSystemTypeIsValid(create_info.file_system_type)) { 1032959b6ec49be09096cf0a5e7504d2a1ec15ef2b3Chris Lattner NOTREACHED(); 1042959b6ec49be09096cf0a5e7504d2a1ec15ef2b3Chris Lattner return PP_ERROR_FAILED; 1052959b6ec49be09096cf0a5e7504d2a1ec15ef2b3Chris Lattner } 1064c299f5da1013cd36563a82f188c731b2758074dChris Lattner 1070c514f4e2711ab57bf75f26806f7b8584dfbee6fChris Lattner int32_t rv = state_manager_.CheckOperationState( 1084c299f5da1013cd36563a82f188c731b2758074dChris Lattner FileIOStateManager::OPERATION_EXCLUSIVE, false); 1094c299f5da1013cd36563a82f188c731b2758074dChris Lattner if (rv != PP_OK) 1102959b6ec49be09096cf0a5e7504d2a1ec15ef2b3Chris Lattner return rv; 1112959b6ec49be09096cf0a5e7504d2a1ec15ef2b3Chris Lattner 1122959b6ec49be09096cf0a5e7504d2a1ec15ef2b3Chris Lattner file_system_type_ = create_info.file_system_type; 1132959b6ec49be09096cf0a5e7504d2a1ec15ef2b3Chris Lattner // Keep the FileSystem host alive by taking a reference to its resource. The 1142959b6ec49be09096cf0a5e7504d2a1ec15ef2b3Chris Lattner // FileIO host uses the FileSystem host for running tasks. 1152959b6ec49be09096cf0a5e7504d2a1ec15ef2b3Chris Lattner file_system_resource_ = create_info.file_system_plugin_resource; 1162959b6ec49be09096cf0a5e7504d2a1ec15ef2b3Chris Lattner 1172959b6ec49be09096cf0a5e7504d2a1ec15ef2b3Chris Lattner // Take a reference on the FileRef resource while we're opening the file; we 1182959b6ec49be09096cf0a5e7504d2a1ec15ef2b3Chris Lattner // don't want the plugin destroying it during the Open operation. 1194c299f5da1013cd36563a82f188c731b2758074dChris Lattner file_ref_ = enter.resource(); 1200c514f4e2711ab57bf75f26806f7b8584dfbee6fChris Lattner 1210c514f4e2711ab57bf75f26806f7b8584dfbee6fChris Lattner Call<PpapiPluginMsg_FileIO_OpenReply>(BROWSER, 1220c514f4e2711ab57bf75f26806f7b8584dfbee6fChris Lattner PpapiHostMsg_FileIO_Open( 1232959b6ec49be09096cf0a5e7504d2a1ec15ef2b3Chris Lattner file_ref, 1242959b6ec49be09096cf0a5e7504d2a1ec15ef2b3Chris Lattner open_flags), 1252959b6ec49be09096cf0a5e7504d2a1ec15ef2b3Chris Lattner base::Bind(&FileIOResource::OnPluginMsgOpenFileComplete, this, 1262959b6ec49be09096cf0a5e7504d2a1ec15ef2b3Chris Lattner callback)); 1270c514f4e2711ab57bf75f26806f7b8584dfbee6fChris Lattner 1282959b6ec49be09096cf0a5e7504d2a1ec15ef2b3Chris Lattner state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_EXCLUSIVE); 1290c514f4e2711ab57bf75f26806f7b8584dfbee6fChris Lattner return PP_OK_COMPLETIONPENDING; 1300c514f4e2711ab57bf75f26806f7b8584dfbee6fChris Lattner} 1312959b6ec49be09096cf0a5e7504d2a1ec15ef2b3Chris Lattner 1320c514f4e2711ab57bf75f26806f7b8584dfbee6fChris Lattnerint32_t FileIOResource::Query(PP_FileInfo* info, 1330c514f4e2711ab57bf75f26806f7b8584dfbee6fChris Lattner scoped_refptr<TrackedCallback> callback) { 1340c514f4e2711ab57bf75f26806f7b8584dfbee6fChris Lattner int32_t rv = state_manager_.CheckOperationState( 1350c514f4e2711ab57bf75f26806f7b8584dfbee6fChris Lattner FileIOStateManager::OPERATION_EXCLUSIVE, true); 1362959b6ec49be09096cf0a5e7504d2a1ec15ef2b3Chris Lattner if (rv != PP_OK) 1370c514f4e2711ab57bf75f26806f7b8584dfbee6fChris Lattner return rv; 1380c514f4e2711ab57bf75f26806f7b8584dfbee6fChris Lattner if (!info) 1390c514f4e2711ab57bf75f26806f7b8584dfbee6fChris Lattner return PP_ERROR_BADARGUMENT; 1400c514f4e2711ab57bf75f26806f7b8584dfbee6fChris Lattner if (!FileHandleHolder::IsValid(file_handle_)) 1412959b6ec49be09096cf0a5e7504d2a1ec15ef2b3Chris Lattner return PP_ERROR_FAILED; 1420c514f4e2711ab57bf75f26806f7b8584dfbee6fChris Lattner 1430c514f4e2711ab57bf75f26806f7b8584dfbee6fChris Lattner state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_EXCLUSIVE); 1442959b6ec49be09096cf0a5e7504d2a1ec15ef2b3Chris Lattner 1450c514f4e2711ab57bf75f26806f7b8584dfbee6fChris Lattner // If the callback is blocking, perform the task on the calling thread. 146d7908f679eeadc108e09e2aca5faba0b5410ea4aBrian Gaeke if (callback->is_blocking()) { 1472959b6ec49be09096cf0a5e7504d2a1ec15ef2b3Chris Lattner int32_t result = PP_ERROR_FAILED; 148d7908f679eeadc108e09e2aca5faba0b5410ea4aBrian Gaeke base::PlatformFileInfo file_info; 1492959b6ec49be09096cf0a5e7504d2a1ec15ef2b3Chris Lattner // The plugin could release its reference to this instance when we release 1502959b6ec49be09096cf0a5e7504d2a1ec15ef2b3Chris Lattner // the proxy lock below. 1512959b6ec49be09096cf0a5e7504d2a1ec15ef2b3Chris Lattner scoped_refptr<FileIOResource> protect(this); 1529d17740295838f94120646ef619b2e187f2d71bdChris Lattner { 1539d17740295838f94120646ef619b2e187f2d71bdChris Lattner // Release the proxy lock while making a potentially slow file call. 1549d17740295838f94120646ef619b2e187f2d71bdChris Lattner ProxyAutoUnlock unlock; 1553501feab811c86c9659248a4875fc31a3165f84dChris Lattner if (base::GetPlatformFileInfo(file_handle_->raw_handle(), &file_info)) 156726140821f96e3472a8eccef0c67c0b5ad65a1d9Chris Lattner result = PP_OK; 157726140821f96e3472a8eccef0c67c0b5ad65a1d9Chris Lattner } 158055c965bff7c8567e7fae90ffe1e10e109856064Chris Lattner if (result == PP_OK) { 159726140821f96e3472a8eccef0c67c0b5ad65a1d9Chris Lattner // This writes the file info into the plugin's PP_FileInfo struct. 1603501feab811c86c9659248a4875fc31a3165f84dChris Lattner ppapi::PlatformFileInfoToPepperFileInfo(file_info, 161726140821f96e3472a8eccef0c67c0b5ad65a1d9Chris Lattner file_system_type_, 162726140821f96e3472a8eccef0c67c0b5ad65a1d9Chris Lattner info); 163726140821f96e3472a8eccef0c67c0b5ad65a1d9Chris Lattner } 164726140821f96e3472a8eccef0c67c0b5ad65a1d9Chris Lattner state_manager_.SetOperationFinished(); 165726140821f96e3472a8eccef0c67c0b5ad65a1d9Chris Lattner return result; 166e9d883828ad92f3a1d06e3c9e98c4e3df937197dMisha Brukman } 167e9d883828ad92f3a1d06e3c9e98c4e3df937197dMisha Brukman 168e9d883828ad92f3a1d06e3c9e98c4e3df937197dMisha Brukman // For the non-blocking case, post a task to the file thread and add a 169e9d883828ad92f3a1d06e3c9e98c4e3df937197dMisha Brukman // completion task to write the result. 170e9d883828ad92f3a1d06e3c9e98c4e3df937197dMisha Brukman scoped_refptr<QueryOp> query_op(new QueryOp(file_handle_)); 171e9d883828ad92f3a1d06e3c9e98c4e3df937197dMisha Brukman base::PostTaskAndReplyWithResult( 17212745c55e1d5a6e76d41684f1b507ea7c6b888acMisha Brukman PpapiGlobals::Get()->GetFileTaskRunner(), 17312745c55e1d5a6e76d41684f1b507ea7c6b888acMisha Brukman FROM_HERE, 17412745c55e1d5a6e76d41684f1b507ea7c6b888acMisha Brukman Bind(&FileIOResource::QueryOp::DoWork, query_op), 175e9d883828ad92f3a1d06e3c9e98c4e3df937197dMisha Brukman RunWhileLocked(Bind(&TrackedCallback::Run, callback))); 176e9d883828ad92f3a1d06e3c9e98c4e3df937197dMisha Brukman callback->set_completion_task( 177e9d883828ad92f3a1d06e3c9e98c4e3df937197dMisha Brukman Bind(&FileIOResource::OnQueryComplete, this, query_op, info)); 178f21dfcddcf199444440004bfa74bb222e2d3ce9eChris Lattner 179f21dfcddcf199444440004bfa74bb222e2d3ce9eChris Lattner return PP_OK_COMPLETIONPENDING; 180f21dfcddcf199444440004bfa74bb222e2d3ce9eChris Lattner} 1814d18d5ce1e62779e7736ca0811e2e1cb06e4ea36Chris Lattner 1824d18d5ce1e62779e7736ca0811e2e1cb06e4ea36Chris Lattnerint32_t FileIOResource::Touch(PP_Time last_access_time, 1834d18d5ce1e62779e7736ca0811e2e1cb06e4ea36Chris Lattner PP_Time last_modified_time, 184726140821f96e3472a8eccef0c67c0b5ad65a1d9Chris Lattner scoped_refptr<TrackedCallback> callback) { 185726140821f96e3472a8eccef0c67c0b5ad65a1d9Chris Lattner int32_t rv = state_manager_.CheckOperationState( 186d0fde30ce850b78371fd1386338350591f9ff494Brian Gaeke FileIOStateManager::OPERATION_EXCLUSIVE, true); 187d0fde30ce850b78371fd1386338350591f9ff494Brian Gaeke if (rv != PP_OK) 188726140821f96e3472a8eccef0c67c0b5ad65a1d9Chris Lattner return rv; 189 190 Call<PpapiPluginMsg_FileIO_GeneralReply>(BROWSER, 191 PpapiHostMsg_FileIO_Touch(last_access_time, last_modified_time), 192 base::Bind(&FileIOResource::OnPluginMsgGeneralComplete, this, 193 callback)); 194 195 state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_EXCLUSIVE); 196 return PP_OK_COMPLETIONPENDING; 197} 198 199int32_t FileIOResource::Read(int64_t offset, 200 char* buffer, 201 int32_t bytes_to_read, 202 scoped_refptr<TrackedCallback> callback) { 203 int32_t rv = state_manager_.CheckOperationState( 204 FileIOStateManager::OPERATION_READ, true); 205 if (rv != PP_OK) 206 return rv; 207 208 PP_ArrayOutput output_adapter; 209 output_adapter.GetDataBuffer = &DummyGetDataBuffer; 210 output_adapter.user_data = buffer; 211 return ReadValidated(offset, bytes_to_read, output_adapter, callback); 212} 213 214int32_t FileIOResource::ReadToArray(int64_t offset, 215 int32_t max_read_length, 216 PP_ArrayOutput* array_output, 217 scoped_refptr<TrackedCallback> callback) { 218 DCHECK(array_output); 219 int32_t rv = state_manager_.CheckOperationState( 220 FileIOStateManager::OPERATION_READ, true); 221 if (rv != PP_OK) 222 return rv; 223 224 return ReadValidated(offset, max_read_length, *array_output, callback); 225} 226 227int32_t FileIOResource::Write(int64_t offset, 228 const char* buffer, 229 int32_t bytes_to_write, 230 scoped_refptr<TrackedCallback> callback) { 231 int32_t rv = state_manager_.CheckOperationState( 232 FileIOStateManager::OPERATION_WRITE, true); 233 if (rv != PP_OK) 234 return rv; 235 236 // TODO(brettw) it would be nice to use a shared memory buffer for large 237 // writes rather than having to copy to a string (which will involve a number 238 // of extra copies to serialize over IPC). 239 Call<PpapiPluginMsg_FileIO_GeneralReply>(BROWSER, 240 PpapiHostMsg_FileIO_Write(offset, std::string(buffer, bytes_to_write)), 241 base::Bind(&FileIOResource::OnPluginMsgGeneralComplete, this, 242 callback)); 243 244 state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_WRITE); 245 return PP_OK_COMPLETIONPENDING; 246} 247 248int32_t FileIOResource::SetLength(int64_t length, 249 scoped_refptr<TrackedCallback> callback) { 250 int32_t rv = state_manager_.CheckOperationState( 251 FileIOStateManager::OPERATION_EXCLUSIVE, true); 252 if (rv != PP_OK) 253 return rv; 254 255 Call<PpapiPluginMsg_FileIO_GeneralReply>(BROWSER, 256 PpapiHostMsg_FileIO_SetLength(length), 257 base::Bind(&FileIOResource::OnPluginMsgGeneralComplete, this, 258 callback)); 259 260 state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_EXCLUSIVE); 261 return PP_OK_COMPLETIONPENDING; 262} 263 264int32_t FileIOResource::Flush(scoped_refptr<TrackedCallback> callback) { 265 int32_t rv = state_manager_.CheckOperationState( 266 FileIOStateManager::OPERATION_EXCLUSIVE, true); 267 if (rv != PP_OK) 268 return rv; 269 270 Call<PpapiPluginMsg_FileIO_GeneralReply>(BROWSER, 271 PpapiHostMsg_FileIO_Flush(), 272 base::Bind(&FileIOResource::OnPluginMsgGeneralComplete, this, 273 callback)); 274 275 state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_EXCLUSIVE); 276 return PP_OK_COMPLETIONPENDING; 277} 278 279void FileIOResource::Close() { 280 if (file_handle_) { 281 file_handle_ = NULL; 282 } 283 Post(BROWSER, PpapiHostMsg_FileIO_Close()); 284} 285 286int32_t FileIOResource::RequestOSFileHandle( 287 PP_FileHandle* handle, 288 scoped_refptr<TrackedCallback> callback) { 289 int32_t rv = state_manager_.CheckOperationState( 290 FileIOStateManager::OPERATION_EXCLUSIVE, true); 291 if (rv != PP_OK) 292 return rv; 293 294 Call<PpapiPluginMsg_FileIO_RequestOSFileHandleReply>(BROWSER, 295 PpapiHostMsg_FileIO_RequestOSFileHandle(), 296 base::Bind(&FileIOResource::OnPluginMsgRequestOSFileHandleComplete, this, 297 callback, handle)); 298 299 state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_EXCLUSIVE); 300 return PP_OK_COMPLETIONPENDING; 301} 302 303FileIOResource::FileHandleHolder::FileHandleHolder(PP_FileHandle file_handle) 304 : raw_handle_(file_handle) { 305} 306 307// static 308bool FileIOResource::FileHandleHolder::IsValid( 309 const scoped_refptr<FileIOResource::FileHandleHolder>& handle) { 310 return handle && (handle->raw_handle() != base::kInvalidPlatformFileValue); 311} 312 313FileIOResource::FileHandleHolder::~FileHandleHolder() { 314 if (raw_handle_ != base::kInvalidPlatformFileValue) { 315 base::TaskRunner* file_task_runner = 316 PpapiGlobals::Get()->GetFileTaskRunner(); 317 file_task_runner->PostTask(FROM_HERE, 318 base::Bind(&DoClose, raw_handle_)); 319 } 320} 321 322int32_t FileIOResource::ReadValidated(int64_t offset, 323 int32_t bytes_to_read, 324 const PP_ArrayOutput& array_output, 325 scoped_refptr<TrackedCallback> callback) { 326 if (bytes_to_read < 0) 327 return PP_ERROR_FAILED; 328 if (!FileHandleHolder::IsValid(file_handle_)) 329 return PP_ERROR_FAILED; 330 331 state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_READ); 332 333 bytes_to_read = std::min(bytes_to_read, kMaxReadSize); 334 if (callback->is_blocking()) { 335 char* buffer = static_cast<char*>( 336 array_output.GetDataBuffer(array_output.user_data, bytes_to_read, 1)); 337 int32_t result = PP_ERROR_FAILED; 338 // The plugin could release its reference to this instance when we release 339 // the proxy lock below. 340 scoped_refptr<FileIOResource> protect(this); 341 if (buffer) { 342 // Release the proxy lock while making a potentially slow file call. 343 ProxyAutoUnlock unlock; 344 result = base::ReadPlatformFile( 345 file_handle_->raw_handle(), offset, buffer, bytes_to_read); 346 if (result < 0) 347 result = PP_ERROR_FAILED; 348 } 349 state_manager_.SetOperationFinished(); 350 return result; 351 } 352 353 // For the non-blocking case, post a task to the file thread. 354 scoped_refptr<ReadOp> read_op( 355 new ReadOp(file_handle_, offset, bytes_to_read)); 356 base::PostTaskAndReplyWithResult( 357 PpapiGlobals::Get()->GetFileTaskRunner(), 358 FROM_HERE, 359 Bind(&FileIOResource::ReadOp::DoWork, read_op), 360 RunWhileLocked(Bind(&TrackedCallback::Run, callback))); 361 callback->set_completion_task( 362 Bind(&FileIOResource::OnReadComplete, this, read_op, array_output)); 363 364 return PP_OK_COMPLETIONPENDING; 365} 366 367int32_t FileIOResource::OnQueryComplete(scoped_refptr<QueryOp> query_op, 368 PP_FileInfo* info, 369 int32_t result) { 370 DCHECK(state_manager_.get_pending_operation() == 371 FileIOStateManager::OPERATION_EXCLUSIVE); 372 373 if (result == PP_OK) { 374 // This writes the file info into the plugin's PP_FileInfo struct. 375 ppapi::PlatformFileInfoToPepperFileInfo(query_op->file_info(), 376 file_system_type_, 377 info); 378 } 379 state_manager_.SetOperationFinished(); 380 return result; 381} 382 383int32_t FileIOResource::OnReadComplete(scoped_refptr<ReadOp> read_op, 384 PP_ArrayOutput array_output, 385 int32_t result) { 386 DCHECK(state_manager_.get_pending_operation() == 387 FileIOStateManager::OPERATION_READ); 388 if (result >= 0) { 389 ArrayWriter output; 390 output.set_pp_array_output(array_output); 391 if (output.is_valid()) 392 output.StoreArray(read_op->buffer(), result); 393 else 394 result = PP_ERROR_FAILED; 395 } else { 396 // The read operation failed. 397 result = PP_ERROR_FAILED; 398 } 399 state_manager_.SetOperationFinished(); 400 return result; 401} 402 403void FileIOResource::OnPluginMsgGeneralComplete( 404 scoped_refptr<TrackedCallback> callback, 405 const ResourceMessageReplyParams& params) { 406 DCHECK(state_manager_.get_pending_operation() == 407 FileIOStateManager::OPERATION_EXCLUSIVE || 408 state_manager_.get_pending_operation() == 409 FileIOStateManager::OPERATION_WRITE); 410 // End this operation now, so the user's callback can execute another FileIO 411 // operation, assuming there are no other pending operations. 412 state_manager_.SetOperationFinished(); 413 callback->Run(params.result()); 414} 415 416void FileIOResource::OnPluginMsgOpenFileComplete( 417 scoped_refptr<TrackedCallback> callback, 418 const ResourceMessageReplyParams& params) { 419 DCHECK(state_manager_.get_pending_operation() == 420 FileIOStateManager::OPERATION_EXCLUSIVE); 421 422 // Release the FileRef resource. 423 file_ref_ = NULL; 424 if (params.result() == PP_OK) 425 state_manager_.SetOpenSucceed(); 426 427 int32_t result = params.result(); 428 IPC::PlatformFileForTransit transit_file; 429 if ((result == PP_OK) && params.TakeFileHandleAtIndex(0, &transit_file)) { 430 file_handle_ = new FileHandleHolder( 431 IPC::PlatformFileForTransitToPlatformFile(transit_file)); 432 } 433 // End this operation now, so the user's callback can execute another FileIO 434 // operation, assuming there are no other pending operations. 435 state_manager_.SetOperationFinished(); 436 callback->Run(result); 437} 438 439void FileIOResource::OnPluginMsgRequestOSFileHandleComplete( 440 scoped_refptr<TrackedCallback> callback, 441 PP_FileHandle* output_handle, 442 const ResourceMessageReplyParams& params) { 443 DCHECK(state_manager_.get_pending_operation() == 444 FileIOStateManager::OPERATION_EXCLUSIVE); 445 446 if (!TrackedCallback::IsPending(callback)) { 447 state_manager_.SetOperationFinished(); 448 return; 449 } 450 451 int32_t result = params.result(); 452 IPC::PlatformFileForTransit transit_file; 453 if (!params.TakeFileHandleAtIndex(0, &transit_file)) 454 result = PP_ERROR_FAILED; 455 *output_handle = IPC::PlatformFileForTransitToPlatformFile(transit_file); 456 457 // End this operation now, so the user's callback can execute another FileIO 458 // operation, assuming there are no other pending operations. 459 state_manager_.SetOperationFinished(); 460 callback->Run(result); 461} 462 463} // namespace proxy 464} // namespace ppapi 465