file_io_resource.cc revision a36e5920737c6adbddd3e43b760e5de8431db6e0
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 "ipc/ipc_message.h" 9#include "ppapi/c/pp_errors.h" 10#include "ppapi/proxy/ppapi_messages.h" 11#include "ppapi/shared_impl/array_writer.h" 12#include "ppapi/shared_impl/ppapi_globals.h" 13#include "ppapi/shared_impl/resource_tracker.h" 14#include "ppapi/thunk/enter.h" 15#include "ppapi/thunk/ppb_file_ref_api.h" 16 17using ppapi::thunk::EnterResourceNoLock; 18using ppapi::thunk::PPB_FileIO_API; 19using ppapi::thunk::PPB_FileRef_API; 20 21namespace { 22 23// An adapter to let Read() share the same implementation with ReadToArray(). 24void* DummyGetDataBuffer(void* user_data, uint32_t count, uint32_t size) { 25 return user_data; 26} 27 28} // namespace 29 30namespace ppapi { 31namespace proxy { 32 33FileIOResource::FileIOResource(Connection connection, PP_Instance instance) 34 : PluginResource(connection, instance) { 35 SendCreate(RENDERER, PpapiHostMsg_FileIO_Create()); 36} 37 38FileIOResource::~FileIOResource() { 39} 40 41PPB_FileIO_API* FileIOResource::AsPPB_FileIO_API() { 42 return this; 43} 44 45int32_t FileIOResource::Open(PP_Resource file_ref, 46 int32_t open_flags, 47 scoped_refptr<TrackedCallback> callback) { 48 EnterResourceNoLock<PPB_FileRef_API> enter(file_ref, true); 49 if (enter.failed()) 50 return PP_ERROR_BADRESOURCE; 51 52 int32_t rv = state_manager_.CheckOperationState( 53 FileIOStateManager::OPERATION_EXCLUSIVE, false); 54 if (rv != PP_OK) 55 return rv; 56 57 Call<PpapiPluginMsg_FileIO_OpenReply>(RENDERER, 58 PpapiHostMsg_FileIO_Open( 59 enter.resource()->host_resource().host_resource(), 60 open_flags), 61 base::Bind(&FileIOResource::OnPluginMsgOpenFileComplete, this, 62 callback)); 63 64 state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_EXCLUSIVE); 65 return PP_OK_COMPLETIONPENDING; 66} 67 68int32_t FileIOResource::Query(PP_FileInfo* info, 69 scoped_refptr<TrackedCallback> callback) { 70 int32_t rv = state_manager_.CheckOperationState( 71 FileIOStateManager::OPERATION_EXCLUSIVE, true); 72 if (rv != PP_OK) 73 return rv; 74 75 Call<PpapiPluginMsg_FileIO_QueryReply>(RENDERER, 76 PpapiHostMsg_FileIO_Query(), 77 base::Bind(&FileIOResource::OnPluginMsgQueryComplete, this, 78 callback, info)); 79 80 state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_EXCLUSIVE); 81 return PP_OK_COMPLETIONPENDING; 82} 83 84int32_t FileIOResource::Touch(PP_Time last_access_time, 85 PP_Time last_modified_time, 86 scoped_refptr<TrackedCallback> callback) { 87 int32_t rv = state_manager_.CheckOperationState( 88 FileIOStateManager::OPERATION_EXCLUSIVE, true); 89 if (rv != PP_OK) 90 return rv; 91 92 Call<PpapiPluginMsg_FileIO_GeneralReply>(RENDERER, 93 PpapiHostMsg_FileIO_Touch(last_access_time, last_modified_time), 94 base::Bind(&FileIOResource::OnPluginMsgGeneralComplete, this, 95 callback)); 96 97 state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_EXCLUSIVE); 98 return PP_OK_COMPLETIONPENDING; 99} 100 101int32_t FileIOResource::Read(int64_t offset, 102 char* buffer, 103 int32_t bytes_to_read, 104 scoped_refptr<TrackedCallback> callback) { 105 int32_t rv = state_manager_.CheckOperationState( 106 FileIOStateManager::OPERATION_READ, true); 107 if (rv != PP_OK) 108 return rv; 109 110 PP_ArrayOutput output_adapter; 111 output_adapter.GetDataBuffer = &DummyGetDataBuffer; 112 output_adapter.user_data = buffer; 113 state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_READ); 114 return ReadValidated(offset, bytes_to_read, output_adapter, callback); 115} 116 117int32_t FileIOResource::ReadToArray(int64_t offset, 118 int32_t max_read_length, 119 PP_ArrayOutput* array_output, 120 scoped_refptr<TrackedCallback> callback) { 121 DCHECK(array_output); 122 int32_t rv = state_manager_.CheckOperationState( 123 FileIOStateManager::OPERATION_READ, true); 124 if (rv != PP_OK) 125 return rv; 126 127 state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_READ); 128 return ReadValidated(offset, max_read_length, *array_output, callback); 129} 130 131int32_t FileIOResource::Write(int64_t offset, 132 const char* buffer, 133 int32_t bytes_to_write, 134 scoped_refptr<TrackedCallback> callback) { 135 int32_t rv = state_manager_.CheckOperationState( 136 FileIOStateManager::OPERATION_WRITE, true); 137 if (rv != PP_OK) 138 return rv; 139 140 // TODO(brettw) it would be nice to use a shared memory buffer for large 141 // writes rather than having to copy to a string (which will involve a number 142 // of extra copies to serialize over IPC). 143 Call<PpapiPluginMsg_FileIO_GeneralReply>(RENDERER, 144 PpapiHostMsg_FileIO_Write(offset, std::string(buffer, bytes_to_write)), 145 base::Bind(&FileIOResource::OnPluginMsgGeneralComplete, this, 146 callback)); 147 148 state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_WRITE); 149 return PP_OK_COMPLETIONPENDING; 150} 151 152int32_t FileIOResource::SetLength(int64_t length, 153 scoped_refptr<TrackedCallback> callback) { 154 int32_t rv = state_manager_.CheckOperationState( 155 FileIOStateManager::OPERATION_EXCLUSIVE, true); 156 if (rv != PP_OK) 157 return rv; 158 159 Call<PpapiPluginMsg_FileIO_GeneralReply>(RENDERER, 160 PpapiHostMsg_FileIO_SetLength(length), 161 base::Bind(&FileIOResource::OnPluginMsgGeneralComplete, this, 162 callback)); 163 164 state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_EXCLUSIVE); 165 return PP_OK_COMPLETIONPENDING; 166} 167 168int32_t FileIOResource::Flush(scoped_refptr<TrackedCallback> callback) { 169 int32_t rv = state_manager_.CheckOperationState( 170 FileIOStateManager::OPERATION_EXCLUSIVE, true); 171 if (rv != PP_OK) 172 return rv; 173 174 Call<PpapiPluginMsg_FileIO_GeneralReply>(RENDERER, 175 PpapiHostMsg_FileIO_Flush(), 176 base::Bind(&FileIOResource::OnPluginMsgGeneralComplete, this, 177 callback)); 178 179 state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_EXCLUSIVE); 180 return PP_OK_COMPLETIONPENDING; 181} 182 183void FileIOResource::Close() { 184 Post(RENDERER, PpapiHostMsg_FileIO_Close()); 185} 186 187int32_t FileIOResource::GetOSFileDescriptor() { 188 int32_t file_descriptor; 189 // Only available when running in process. 190 SyncCall<PpapiPluginMsg_FileIO_GetOSFileDescriptorReply>( 191 RENDERER, PpapiHostMsg_FileIO_GetOSFileDescriptor(), &file_descriptor); 192 return file_descriptor; 193} 194 195int32_t FileIOResource::WillWrite(int64_t offset, 196 int32_t bytes_to_write, 197 scoped_refptr<TrackedCallback> callback) { 198 Call<PpapiPluginMsg_FileIO_GeneralReply>(RENDERER, 199 PpapiHostMsg_FileIO_WillWrite(offset, bytes_to_write), 200 base::Bind(&FileIOResource::OnPluginMsgGeneralComplete, this, 201 callback)); 202 state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_EXCLUSIVE); 203 return PP_OK_COMPLETIONPENDING; 204} 205 206int32_t FileIOResource::WillSetLength(int64_t length, 207 scoped_refptr<TrackedCallback> callback) { 208 Call<PpapiPluginMsg_FileIO_GeneralReply>(RENDERER, 209 PpapiHostMsg_FileIO_WillSetLength(length), 210 base::Bind(&FileIOResource::OnPluginMsgGeneralComplete, this, 211 callback)); 212 state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_EXCLUSIVE); 213 return PP_OK_COMPLETIONPENDING; 214} 215 216int32_t FileIOResource::ReadValidated(int64_t offset, 217 int32_t bytes_to_read, 218 const PP_ArrayOutput& array_output, 219 scoped_refptr<TrackedCallback> callback) { 220 Call<PpapiPluginMsg_FileIO_ReadReply>(RENDERER, 221 PpapiHostMsg_FileIO_Read(offset, bytes_to_read), 222 base::Bind(&FileIOResource::OnPluginMsgReadComplete, this, 223 callback, array_output)); 224 return PP_OK_COMPLETIONPENDING; 225} 226 227int32_t FileIOResource::RequestOSFileHandle( 228 PP_FileHandle* handle, 229 scoped_refptr<TrackedCallback> callback) { 230 int32_t rv = state_manager_.CheckOperationState( 231 FileIOStateManager::OPERATION_EXCLUSIVE, true); 232 if (rv != PP_OK) 233 return rv; 234 235 Call<PpapiPluginMsg_FileIO_RequestOSFileHandleReply>(RENDERER, 236 PpapiHostMsg_FileIO_RequestOSFileHandle(), 237 base::Bind(&FileIOResource::OnPluginMsgRequestOSFileHandleComplete, this, 238 callback, handle)); 239 240 state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_EXCLUSIVE); 241 return PP_OK_COMPLETIONPENDING; 242} 243 244void FileIOResource::OnPluginMsgGeneralComplete( 245 scoped_refptr<TrackedCallback> callback, 246 const ResourceMessageReplyParams& params) { 247 DCHECK(state_manager_.get_pending_operation() == 248 FileIOStateManager::OPERATION_EXCLUSIVE || 249 state_manager_.get_pending_operation() == 250 FileIOStateManager::OPERATION_WRITE); 251 // End the operation now. The callback may perform another file operation. 252 state_manager_.SetOperationFinished(); 253 callback->Run(params.result()); 254} 255 256void FileIOResource::OnPluginMsgOpenFileComplete( 257 scoped_refptr<TrackedCallback> callback, 258 const ResourceMessageReplyParams& params) { 259 DCHECK(state_manager_.get_pending_operation() == 260 FileIOStateManager::OPERATION_EXCLUSIVE); 261 if (params.result() == PP_OK) 262 state_manager_.SetOpenSucceed(); 263 // End the operation now. The callback may perform another file operation. 264 state_manager_.SetOperationFinished(); 265 callback->Run(params.result()); 266} 267 268void FileIOResource::OnPluginMsgQueryComplete( 269 scoped_refptr<TrackedCallback> callback, 270 PP_FileInfo* output_info, 271 const ResourceMessageReplyParams& params, 272 const PP_FileInfo& info) { 273 DCHECK(state_manager_.get_pending_operation() == 274 FileIOStateManager::OPERATION_EXCLUSIVE); 275 *output_info = info; 276 // End the operation now. The callback may perform another file operation. 277 state_manager_.SetOperationFinished(); 278 callback->Run(params.result()); 279} 280 281void FileIOResource::OnPluginMsgReadComplete( 282 scoped_refptr<TrackedCallback> callback, 283 PP_ArrayOutput array_output, 284 const ResourceMessageReplyParams& params, 285 const std::string& data) { 286 DCHECK(state_manager_.get_pending_operation() == 287 FileIOStateManager::OPERATION_READ); 288 289 // The result code should contain the data size if it's positive. 290 int32_t result = params.result(); 291 DCHECK((result < 0 && data.size() == 0) || 292 result == static_cast<int32_t>(data.size())); 293 294 ArrayWriter output; 295 output.set_pp_array_output(array_output); 296 if (output.is_valid()) 297 output.StoreArray(data.data(), std::max(0, result)); 298 else 299 result = PP_ERROR_FAILED; 300 301 // End the operation now. The callback may perform another file operation. 302 state_manager_.SetOperationFinished(); 303 callback->Run(result); 304} 305 306void FileIOResource::OnPluginMsgRequestOSFileHandleComplete( 307 scoped_refptr<TrackedCallback> callback, 308 PP_FileHandle* output_handle, 309 const ResourceMessageReplyParams& params) { 310 DCHECK(state_manager_.get_pending_operation() == 311 FileIOStateManager::OPERATION_EXCLUSIVE); 312 313 if (!TrackedCallback::IsPending(callback)) { 314 state_manager_.SetOperationFinished(); 315 return; 316 } 317 318 int32_t result = params.result(); 319 IPC::PlatformFileForTransit transit_file; 320 if (!params.TakeFileHandleAtIndex(0, &transit_file)) 321 result = PP_ERROR_FAILED; 322 *output_handle = IPC::PlatformFileForTransitToPlatformFile(transit_file); 323 324 // End the operation now. The callback may perform another file operation. 325 state_manager_.SetOperationFinished(); 326 callback->Run(result); 327} 328 329} // namespace proxy 330} // namespace ppapi 331