| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2011 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/ppb_flash_file_proxy.h" | |
| 6 | |
| 7 #include <map> | |
| 8 #include <set> | |
| 9 #include <vector> | |
| 10 | |
| 11 #include "base/bind.h" | |
| 12 #include "base/logging.h" | |
| 13 #include "base/message_loop_proxy.h" | |
| 14 #include "base/synchronization/lock.h" | |
| 15 #include "base/synchronization/waitable_event.h" | |
| 16 #include "build/build_config.h" | |
| 17 #include "ipc/ipc_channel_proxy.h" | |
| 18 #include "ipc/ipc_message.h" | |
| 19 #include "ipc/ipc_sync_message.h" | |
| 20 #include "ppapi/c/pp_errors.h" | |
| 21 #include "ppapi/c/pp_file_info.h" | |
| 22 #include "ppapi/c/private/ppb_flash_file.h" | |
| 23 #include "ppapi/proxy/plugin_dispatcher.h" | |
| 24 #include "ppapi/proxy/ppapi_messages.h" | |
| 25 #include "ppapi/shared_impl/ppapi_globals.h" | |
| 26 #include "ppapi/shared_impl/resource.h" | |
| 27 #include "ppapi/shared_impl/resource_tracker.h" | |
| 28 | |
| 29 namespace ppapi { | |
| 30 namespace proxy { | |
| 31 | |
| 32 namespace { | |
| 33 | |
| 34 // Given an error code and a handle result from a Pepper API call, converts to a | |
| 35 // PlatformFileForTransit by sharing with the other side, closing the original | |
| 36 // handle, possibly also updating the error value if an error occurred. | |
| 37 IPC::PlatformFileForTransit PlatformFileToPlatformFileForTransit( | |
| 38 Dispatcher* dispatcher, | |
| 39 int32_t* error, | |
| 40 base::PlatformFile file) { | |
| 41 if (*error != PP_OK) | |
| 42 return IPC::InvalidPlatformFileForTransit(); | |
| 43 IPC::PlatformFileForTransit out_handle = | |
| 44 dispatcher->ShareHandleWithRemote(file, true); | |
| 45 if (out_handle == IPC::InvalidPlatformFileForTransit()) | |
| 46 *error = PP_ERROR_NOACCESS; | |
| 47 return out_handle; | |
| 48 } | |
| 49 | |
| 50 void FreeDirContents(PP_Instance /* instance */, | |
| 51 PP_DirContents_Dev* contents) { | |
| 52 for (int32_t i = 0; i < contents->count; ++i) | |
| 53 delete[] contents->entries[i].name; | |
| 54 delete[] contents->entries; | |
| 55 delete contents; | |
| 56 } | |
| 57 | |
| 58 } // namespace | |
| 59 | |
| 60 // ModuleLocalThreadAdapter ---------------------------------------------------- | |
| 61 // TODO(yzshen): Refactor to use IPC::SyncMessageFilter. | |
| 62 class ModuleLocalThreadAdapter | |
| 63 : public base::RefCountedThreadSafe<ModuleLocalThreadAdapter> { | |
| 64 class Filter; | |
| 65 public: | |
| 66 ModuleLocalThreadAdapter(); | |
| 67 | |
| 68 void AddInstanceRouting(PP_Instance instance, Dispatcher* dispatcher); | |
| 69 void ClearInstanceRouting(PP_Instance instance); | |
| 70 void ClearFilter(Dispatcher* dispatcher, Filter* filter); | |
| 71 | |
| 72 bool OnModuleLocalMessageReceived(const IPC::Message& msg); | |
| 73 | |
| 74 // Called on the I/O thread when the channel is being destroyed and the | |
| 75 // given message will never be issued a reply. | |
| 76 void OnModuleLocalMessageFailed(int message_id); | |
| 77 | |
| 78 bool Send(PP_Instance instance, IPC::Message* msg); | |
| 79 | |
| 80 private: | |
| 81 class Filter : public IPC::ChannelProxy::MessageFilter { | |
| 82 public: | |
| 83 explicit Filter(Dispatcher* dispatcher); | |
| 84 ~Filter(); | |
| 85 | |
| 86 void Send(IPC::Message* msg); | |
| 87 | |
| 88 virtual void OnFilterAdded(IPC::Channel* channel); | |
| 89 virtual void OnFilterRemoved(); | |
| 90 virtual bool OnMessageReceived(const IPC::Message& message); | |
| 91 | |
| 92 private: | |
| 93 // DO NOT DEREFERENCE! This is used only for tracking. | |
| 94 Dispatcher* dispatcher_; | |
| 95 | |
| 96 IPC::Channel* channel_; | |
| 97 | |
| 98 // Holds the IPC messages that were sent before the channel was connected. | |
| 99 // These will be sent ASAP. | |
| 100 std::vector<IPC::Message*> pre_connect_pending_messages_; | |
| 101 | |
| 102 // Holds the IDs of the sync messages we're currently waiting on for this | |
| 103 // channel. This tracking allows us to cancel those requests if the | |
| 104 // remote process crashes and we're cleaning up this filter (without just | |
| 105 // deadlocking the waiting thread(s). | |
| 106 std::set<int> pending_requests_for_filter_; | |
| 107 }; | |
| 108 | |
| 109 void SendFromIOThread(Dispatcher* dispatcher, IPC::Message* msg); | |
| 110 | |
| 111 // Internal version of OnModuleLocalMessageFailed which assumes the lock | |
| 112 // is already held. | |
| 113 void OnModuleLocalMessageFailedLocked(int message_id); | |
| 114 | |
| 115 base::Lock lock_; | |
| 116 | |
| 117 scoped_refptr<base::MessageLoopProxy> main_thread_; | |
| 118 | |
| 119 // Will be NULL before an instance routing is added. | |
| 120 scoped_refptr<base::MessageLoopProxy> io_thread_; | |
| 121 | |
| 122 typedef std::map<PP_Instance, Dispatcher*> InstanceToDispatcher; | |
| 123 InstanceToDispatcher instance_to_dispatcher_; | |
| 124 | |
| 125 // The filters are owned by the channel. | |
| 126 typedef std::map<Dispatcher*, Filter*> DispatcherToFilter; | |
| 127 DispatcherToFilter dispatcher_to_filter_; | |
| 128 | |
| 129 // Tracks all messages with currently waiting threads. This does not own | |
| 130 // the pointer, the pointer lifetime is managed by Send(). | |
| 131 typedef std::map<int, IPC::PendingSyncMsg*> SyncRequestMap; | |
| 132 SyncRequestMap pending_sync_requests_; | |
| 133 }; | |
| 134 | |
| 135 ModuleLocalThreadAdapter* g_module_local_thread_adapter = NULL; | |
| 136 | |
| 137 ModuleLocalThreadAdapter::Filter::Filter(Dispatcher* dispatcher) | |
| 138 : dispatcher_(dispatcher), channel_(NULL) { | |
| 139 } | |
| 140 | |
| 141 ModuleLocalThreadAdapter::Filter::~Filter() { | |
| 142 } | |
| 143 | |
| 144 void ModuleLocalThreadAdapter::Filter::Send(IPC::Message* msg) { | |
| 145 if (channel_) { | |
| 146 int message_id = IPC::SyncMessage::GetMessageId(*msg); | |
| 147 if (channel_->Send(msg)) | |
| 148 pending_requests_for_filter_.insert(message_id); | |
| 149 else // Message lost, notify adapter so it can unblock. | |
| 150 g_module_local_thread_adapter->OnModuleLocalMessageFailed(message_id); | |
| 151 } else { | |
| 152 // No channel, save this message for when it's connected. | |
| 153 pre_connect_pending_messages_.push_back(msg); | |
| 154 } | |
| 155 } | |
| 156 | |
| 157 void ModuleLocalThreadAdapter::Filter::OnFilterAdded(IPC::Channel* channel) { | |
| 158 DCHECK(!channel_); | |
| 159 channel_ = channel; | |
| 160 | |
| 161 // Now that we have a channel, process all pending messages. | |
| 162 for (size_t i = 0; i < pre_connect_pending_messages_.size(); i++) | |
| 163 Send(pre_connect_pending_messages_[i]); | |
| 164 pre_connect_pending_messages_.clear(); | |
| 165 } | |
| 166 | |
| 167 void ModuleLocalThreadAdapter::Filter::OnFilterRemoved() { | |
| 168 DCHECK(channel_); | |
| 169 channel_ = NULL; | |
| 170 g_module_local_thread_adapter->ClearFilter(dispatcher_, this); | |
| 171 | |
| 172 for (std::set<int>::iterator i = pending_requests_for_filter_.begin(); | |
| 173 i != pending_requests_for_filter_.end(); ++i) { | |
| 174 g_module_local_thread_adapter->OnModuleLocalMessageFailed(*i); | |
| 175 } | |
| 176 } | |
| 177 | |
| 178 bool ModuleLocalThreadAdapter::Filter::OnMessageReceived( | |
| 179 const IPC::Message& message) { | |
| 180 if (!message.is_reply() || | |
| 181 message.routing_id() != API_ID_PPB_FLASH_FILE_MODULELOCAL) | |
| 182 return false; | |
| 183 | |
| 184 if (g_module_local_thread_adapter->OnModuleLocalMessageReceived(message)) { | |
| 185 // The message was consumed, this means we can remove the message ID from | |
| 186 // the list of messages this channel is waiting on. | |
| 187 pending_requests_for_filter_.erase(IPC::SyncMessage::GetMessageId(message)); | |
| 188 return true; | |
| 189 } | |
| 190 return false; | |
| 191 } | |
| 192 | |
| 193 ModuleLocalThreadAdapter::ModuleLocalThreadAdapter() | |
| 194 : main_thread_(base::MessageLoopProxy::current()) { | |
| 195 } | |
| 196 | |
| 197 void ModuleLocalThreadAdapter::AddInstanceRouting(PP_Instance instance, | |
| 198 Dispatcher* dispatcher) { | |
| 199 base::AutoLock lock(lock_); | |
| 200 | |
| 201 // Now that we've had contact with a dispatcher, we can set up the IO thread. | |
| 202 DCHECK(main_thread_->BelongsToCurrentThread()); | |
| 203 if (!io_thread_.get()) | |
| 204 io_thread_ = dispatcher->GetIPCMessageLoop(); | |
| 205 | |
| 206 // Set up the instance -> dispatcher routing. | |
| 207 DCHECK(instance_to_dispatcher_.find(instance) == | |
| 208 instance_to_dispatcher_.end()); | |
| 209 instance_to_dispatcher_[instance] = dispatcher; | |
| 210 | |
| 211 DispatcherToFilter::iterator found_filter = | |
| 212 dispatcher_to_filter_.find(dispatcher); | |
| 213 if (found_filter == dispatcher_to_filter_.end()) { | |
| 214 // Need to set up a filter for this dispatcher to intercept the messages. | |
| 215 Filter* filter = new Filter(dispatcher); | |
| 216 dispatcher_to_filter_[dispatcher] = filter; | |
| 217 dispatcher->AddIOThreadMessageFilter(filter); | |
| 218 } | |
| 219 } | |
| 220 | |
| 221 void ModuleLocalThreadAdapter::ClearInstanceRouting(PP_Instance instance) { | |
| 222 // The dispatcher->filter mapping is cleaned up by ClearFilter which is | |
| 223 // initiated by the channel. | |
| 224 instance_to_dispatcher_.erase(instance); | |
| 225 } | |
| 226 | |
| 227 void ModuleLocalThreadAdapter::ClearFilter(Dispatcher* dispatcher, | |
| 228 Filter* filter) { | |
| 229 // DANGER! Don't dereference the dispatcher, it's just used to identify | |
| 230 // which filter to remove. The dispatcher may not even exist any more. | |
| 231 // | |
| 232 // Since the dispatcher may be gone, there's a potential for ambiguity if | |
| 233 // another one is created on the main thread before this code runs on the | |
| 234 // I/O thread. So we check that the filter matches to avoid this rare case. | |
| 235 base::AutoLock lock(lock_); | |
| 236 if (dispatcher_to_filter_[dispatcher] == filter) | |
| 237 dispatcher_to_filter_.erase(dispatcher); | |
| 238 } | |
| 239 | |
| 240 bool ModuleLocalThreadAdapter::OnModuleLocalMessageReceived( | |
| 241 const IPC::Message& msg) { | |
| 242 base::AutoLock lock(lock_); | |
| 243 | |
| 244 int message_id = IPC::SyncMessage::GetMessageId(msg); | |
| 245 SyncRequestMap::iterator found = pending_sync_requests_.find(message_id); | |
| 246 if (found == pending_sync_requests_.end()) { | |
| 247 // Not waiting for this event. This will happen for sync messages to the | |
| 248 // main thread which use the "regular" sync channel code path. | |
| 249 return false; | |
| 250 } | |
| 251 | |
| 252 IPC::PendingSyncMsg& info = *found->second; | |
| 253 | |
| 254 if (!msg.is_reply_error()) | |
| 255 info.deserializer->SerializeOutputParameters(msg); | |
| 256 info.done_event->Signal(); | |
| 257 return true; | |
| 258 } | |
| 259 | |
| 260 void ModuleLocalThreadAdapter::OnModuleLocalMessageFailed(int message_id) { | |
| 261 base::AutoLock lock(lock_); | |
| 262 OnModuleLocalMessageFailedLocked(message_id); | |
| 263 } | |
| 264 | |
| 265 bool ModuleLocalThreadAdapter::Send(PP_Instance instance, IPC::Message* msg) { | |
| 266 // Compute the dispatcher corresponding to this message. | |
| 267 Dispatcher* dispatcher = NULL; | |
| 268 { | |
| 269 base::AutoLock lock(lock_); | |
| 270 InstanceToDispatcher::iterator found = | |
| 271 instance_to_dispatcher_.find(instance); | |
| 272 if (found == instance_to_dispatcher_.end()) { | |
| 273 NOTREACHED(); | |
| 274 delete msg; | |
| 275 return false; | |
| 276 } | |
| 277 dispatcher = found->second; | |
| 278 } | |
| 279 | |
| 280 if (main_thread_->BelongsToCurrentThread()) { | |
| 281 // Easy case: We're on the same thread as the dispatcher, so we don't need | |
| 282 // a lock to access it, and we can just use the normal sync channel stuff | |
| 283 // to handle the message. Actually, we MUST use the normal sync channel | |
| 284 // stuff since there may be incoming sync messages that need processing. | |
| 285 // The code below doesn't handle any nested message loops. | |
| 286 return dispatcher->Send(msg); | |
| 287 } | |
| 288 | |
| 289 // Background thread case | |
| 290 // ---------------------- | |
| 291 // 1. Generate tracking info, stick in pending_sync_messages_map. | |
| 292 // 2. Kick off the request. This is done on the I/O thread. | |
| 293 // 3. Filter on the I/O thread notices reply, writes the reply data and | |
| 294 // signals the event. We block on the event while this is happening. | |
| 295 // 4. Remove tracking info. | |
| 296 | |
| 297 // Generate the tracking info. and copied | |
| 298 IPC::SyncMessage* sync_msg = static_cast<IPC::SyncMessage*>(msg); | |
| 299 int message_id = IPC::SyncMessage::GetMessageId(*sync_msg); | |
| 300 base::WaitableEvent event(true, false); | |
| 301 scoped_ptr<IPC::MessageReplyDeserializer> deserializer( | |
| 302 sync_msg->GetReplyDeserializer()); // We own this pointer once retrieved. | |
| 303 IPC::PendingSyncMsg info(message_id, deserializer.get(), &event); | |
| 304 | |
| 305 // Add the tracking information to our map. | |
| 306 { | |
| 307 base::AutoLock lock(lock_); | |
| 308 pending_sync_requests_[message_id] = &info; | |
| 309 } | |
| 310 | |
| 311 // This is a bit dangerous. We use the dispatcher pointer as the routing | |
| 312 // ID for this message. While we don't dereference it, there is an | |
| 313 // exceedingly remote possibility that while this is going to the background | |
| 314 // thread the connection will be shut down and a new one will be created with | |
| 315 // a dispatcher at the same address. It could potentially get sent to a | |
| 316 // random place, but it should actually still work (since the Flash file | |
| 317 // operations are global). | |
| 318 io_thread_->PostTask(FROM_HERE, | |
| 319 base::Bind(&ModuleLocalThreadAdapter::SendFromIOThread, this, | |
| 320 dispatcher, msg)); | |
| 321 | |
| 322 // Now we block the current thread waiting for the reply. | |
| 323 event.Wait(); | |
| 324 | |
| 325 { | |
| 326 // Clear our tracking info for this message now that we're done. | |
| 327 base::AutoLock lock(lock_); | |
| 328 DCHECK(pending_sync_requests_.find(message_id) != | |
| 329 pending_sync_requests_.end()); | |
| 330 pending_sync_requests_.erase(message_id); | |
| 331 } | |
| 332 | |
| 333 return true; | |
| 334 } | |
| 335 | |
| 336 void ModuleLocalThreadAdapter::SendFromIOThread(Dispatcher* dispatcher, | |
| 337 IPC::Message* msg) { | |
| 338 // DO NOT DEREFERENCE DISPATCHER. Used as a lookup only. | |
| 339 base::AutoLock lock(lock_); | |
| 340 DispatcherToFilter::iterator found = dispatcher_to_filter_.find(dispatcher); | |
| 341 | |
| 342 // The dispatcher could have been destroyed by the time we got here since | |
| 343 // we're on another thread. Need to unblock the caller. | |
| 344 if (found == dispatcher_to_filter_.end()) { | |
| 345 OnModuleLocalMessageFailedLocked(IPC::SyncMessage::GetMessageId(*msg)); | |
| 346 delete msg; | |
| 347 return; | |
| 348 } | |
| 349 | |
| 350 // Takes ownership of pointer. | |
| 351 found->second->Send(msg); | |
| 352 } | |
| 353 | |
| 354 void ModuleLocalThreadAdapter::OnModuleLocalMessageFailedLocked( | |
| 355 int message_id) { | |
| 356 lock_.AssertAcquired(); | |
| 357 | |
| 358 // Unblock the thread waiting for the message that will never come. | |
| 359 SyncRequestMap::iterator found = pending_sync_requests_.find(message_id); | |
| 360 if (found == pending_sync_requests_.end()) { | |
| 361 NOTREACHED(); | |
| 362 return; | |
| 363 } | |
| 364 found->second->done_event->Signal(); | |
| 365 } | |
| 366 | |
| 367 // PPB_Flash_File_ModuleLocal -------------------------------------------------- | |
| 368 | |
| 369 namespace { | |
| 370 | |
| 371 bool CreateThreadAdapterForInstance(PP_Instance instance) { | |
| 372 if (!g_module_local_thread_adapter) { | |
| 373 g_module_local_thread_adapter = new ModuleLocalThreadAdapter(); | |
| 374 g_module_local_thread_adapter->AddRef(); // Leaked, this object is global. | |
| 375 } | |
| 376 | |
| 377 PluginDispatcher* dispatcher = PluginDispatcher::GetForInstance(instance); | |
| 378 if (!dispatcher) { | |
| 379 NOTREACHED(); | |
| 380 return false; | |
| 381 } | |
| 382 g_module_local_thread_adapter->AddInstanceRouting(instance, dispatcher); | |
| 383 return true; | |
| 384 } | |
| 385 | |
| 386 void ClearThreadAdapterForInstance(PP_Instance instance) { | |
| 387 if (g_module_local_thread_adapter) | |
| 388 g_module_local_thread_adapter->ClearInstanceRouting(instance); | |
| 389 } | |
| 390 | |
| 391 int32_t OpenModuleLocalFile(PP_Instance instance, | |
| 392 const char* path, | |
| 393 int32_t mode, | |
| 394 PP_FileHandle* file) { | |
| 395 if (!g_module_local_thread_adapter) | |
| 396 return PP_ERROR_FAILED; | |
| 397 | |
| 398 int32_t result = PP_ERROR_FAILED; | |
| 399 IPC::PlatformFileForTransit transit; | |
| 400 g_module_local_thread_adapter->Send(instance, | |
| 401 new PpapiHostMsg_PPBFlashFile_ModuleLocal_OpenFile( | |
| 402 API_ID_PPB_FLASH_FILE_MODULELOCAL, | |
| 403 instance, path, mode, &transit, &result)); | |
| 404 *file = IPC::PlatformFileForTransitToPlatformFile(transit); | |
| 405 return result; | |
| 406 } | |
| 407 | |
| 408 int32_t RenameModuleLocalFile(PP_Instance instance, | |
| 409 const char* from_path, | |
| 410 const char* to_path) { | |
| 411 if (!g_module_local_thread_adapter) | |
| 412 return PP_ERROR_FAILED; | |
| 413 | |
| 414 int32_t result = PP_ERROR_FAILED; | |
| 415 g_module_local_thread_adapter->Send(instance, | |
| 416 new PpapiHostMsg_PPBFlashFile_ModuleLocal_RenameFile( | |
| 417 API_ID_PPB_FLASH_FILE_MODULELOCAL, | |
| 418 instance, from_path, to_path, &result)); | |
| 419 return result; | |
| 420 } | |
| 421 | |
| 422 int32_t DeleteModuleLocalFileOrDir(PP_Instance instance, | |
| 423 const char* path, | |
| 424 PP_Bool recursive) { | |
| 425 if (!g_module_local_thread_adapter) | |
| 426 return PP_ERROR_FAILED; | |
| 427 | |
| 428 int32_t result = PP_ERROR_FAILED; | |
| 429 g_module_local_thread_adapter->Send(instance, | |
| 430 new PpapiHostMsg_PPBFlashFile_ModuleLocal_DeleteFileOrDir( | |
| 431 API_ID_PPB_FLASH_FILE_MODULELOCAL, | |
| 432 instance, path, recursive, &result)); | |
| 433 return result; | |
| 434 } | |
| 435 | |
| 436 int32_t CreateModuleLocalDir(PP_Instance instance, const char* path) { | |
| 437 if (!g_module_local_thread_adapter) | |
| 438 return PP_ERROR_FAILED; | |
| 439 | |
| 440 int32_t result = PP_ERROR_FAILED; | |
| 441 g_module_local_thread_adapter->Send(instance, | |
| 442 new PpapiHostMsg_PPBFlashFile_ModuleLocal_CreateDir( | |
| 443 API_ID_PPB_FLASH_FILE_MODULELOCAL, instance, path, &result)); | |
| 444 return result; | |
| 445 } | |
| 446 | |
| 447 int32_t QueryModuleLocalFile(PP_Instance instance, | |
| 448 const char* path, | |
| 449 PP_FileInfo* info) { | |
| 450 if (!g_module_local_thread_adapter) | |
| 451 return PP_ERROR_FAILED; | |
| 452 | |
| 453 int32_t result = PP_ERROR_FAILED; | |
| 454 g_module_local_thread_adapter->Send(instance, | |
| 455 new PpapiHostMsg_PPBFlashFile_ModuleLocal_QueryFile( | |
| 456 API_ID_PPB_FLASH_FILE_MODULELOCAL, instance, path, | |
| 457 info, &result)); | |
| 458 return result; | |
| 459 } | |
| 460 | |
| 461 int32_t GetModuleLocalDirContents(PP_Instance instance, | |
| 462 const char* path, | |
| 463 PP_DirContents_Dev** contents) { | |
| 464 if (!g_module_local_thread_adapter) | |
| 465 return PP_ERROR_FAILED; | |
| 466 | |
| 467 int32_t result = PP_ERROR_FAILED; | |
| 468 std::vector<SerializedDirEntry> entries; | |
| 469 g_module_local_thread_adapter->Send(instance, | |
| 470 new PpapiHostMsg_PPBFlashFile_ModuleLocal_GetDirContents( | |
| 471 API_ID_PPB_FLASH_FILE_MODULELOCAL, | |
| 472 instance, path, &entries, &result)); | |
| 473 | |
| 474 if (result != PP_OK) | |
| 475 return result; | |
| 476 | |
| 477 // Copy the serialized dir entries to the output struct. | |
| 478 *contents = new PP_DirContents_Dev; | |
| 479 (*contents)->count = static_cast<int32_t>(entries.size()); | |
| 480 (*contents)->entries = new PP_DirEntry_Dev[entries.size()]; | |
| 481 for (size_t i = 0; i < entries.size(); i++) { | |
| 482 const SerializedDirEntry& source = entries[i]; | |
| 483 PP_DirEntry_Dev* dest = &(*contents)->entries[i]; | |
| 484 | |
| 485 char* name_copy = new char[source.name.size() + 1]; | |
| 486 memcpy(name_copy, source.name.c_str(), source.name.size() + 1); | |
| 487 dest->name = name_copy; | |
| 488 dest->is_dir = PP_FromBool(source.is_dir); | |
| 489 } | |
| 490 | |
| 491 return result; | |
| 492 } | |
| 493 | |
| 494 const PPB_Flash_File_ModuleLocal flash_file_modulelocal_interface = { | |
| 495 &CreateThreadAdapterForInstance, | |
| 496 &ClearThreadAdapterForInstance, | |
| 497 &OpenModuleLocalFile, | |
| 498 &RenameModuleLocalFile, | |
| 499 &DeleteModuleLocalFileOrDir, | |
| 500 &CreateModuleLocalDir, | |
| 501 &QueryModuleLocalFile, | |
| 502 &GetModuleLocalDirContents, | |
| 503 &FreeDirContents, | |
| 504 }; | |
| 505 | |
| 506 InterfaceProxy* CreateFlashFileModuleLocalProxy(Dispatcher* dispatcher) { | |
| 507 return new PPB_Flash_File_ModuleLocal_Proxy(dispatcher); | |
| 508 } | |
| 509 | |
| 510 } // namespace | |
| 511 | |
| 512 PPB_Flash_File_ModuleLocal_Proxy::PPB_Flash_File_ModuleLocal_Proxy( | |
| 513 Dispatcher* dispatcher) | |
| 514 : InterfaceProxy(dispatcher), | |
| 515 ppb_flash_file_module_local_impl_(NULL) { | |
| 516 if (!dispatcher->IsPlugin()) { | |
| 517 ppb_flash_file_module_local_impl_ = | |
| 518 static_cast<const PPB_Flash_File_ModuleLocal*>( | |
| 519 dispatcher->local_get_interface()( | |
| 520 PPB_FLASH_FILE_MODULELOCAL_INTERFACE)); | |
| 521 } | |
| 522 } | |
| 523 | |
| 524 PPB_Flash_File_ModuleLocal_Proxy::~PPB_Flash_File_ModuleLocal_Proxy() { | |
| 525 } | |
| 526 | |
| 527 // static | |
| 528 const PPB_Flash_File_ModuleLocal* | |
| 529 PPB_Flash_File_ModuleLocal_Proxy::GetInterface() { | |
| 530 return &flash_file_modulelocal_interface; | |
| 531 } | |
| 532 | |
| 533 bool PPB_Flash_File_ModuleLocal_Proxy::OnMessageReceived( | |
| 534 const IPC::Message& msg) { | |
| 535 bool handled = true; | |
| 536 IPC_BEGIN_MESSAGE_MAP(PPB_Flash_File_ModuleLocal_Proxy, msg) | |
| 537 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBFlashFile_ModuleLocal_OpenFile, | |
| 538 OnMsgOpenFile) | |
| 539 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBFlashFile_ModuleLocal_RenameFile, | |
| 540 OnMsgRenameFile) | |
| 541 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBFlashFile_ModuleLocal_DeleteFileOrDir, | |
| 542 OnMsgDeleteFileOrDir) | |
| 543 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBFlashFile_ModuleLocal_CreateDir, | |
| 544 OnMsgCreateDir) | |
| 545 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBFlashFile_ModuleLocal_QueryFile, | |
| 546 OnMsgQueryFile) | |
| 547 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBFlashFile_ModuleLocal_GetDirContents, | |
| 548 OnMsgGetDirContents) | |
| 549 IPC_MESSAGE_UNHANDLED(handled = false) | |
| 550 IPC_END_MESSAGE_MAP() | |
| 551 // TODO(brettw) handle bad messages! | |
| 552 return handled; | |
| 553 } | |
| 554 | |
| 555 void PPB_Flash_File_ModuleLocal_Proxy::OnMsgOpenFile( | |
| 556 PP_Instance instance, | |
| 557 const std::string& path, | |
| 558 int32_t mode, | |
| 559 IPC::PlatformFileForTransit* file_handle, | |
| 560 int32_t* result) { | |
| 561 base::PlatformFile file; | |
| 562 *result = ppb_flash_file_module_local_impl_->OpenFile( | |
| 563 instance, path.c_str(), mode, &file); | |
| 564 *file_handle = PlatformFileToPlatformFileForTransit( | |
| 565 dispatcher(), result, file); | |
| 566 } | |
| 567 | |
| 568 void PPB_Flash_File_ModuleLocal_Proxy::OnMsgRenameFile( | |
| 569 PP_Instance instance, | |
| 570 const std::string& from_path, | |
| 571 const std::string& to_path, | |
| 572 int32_t* result) { | |
| 573 *result = ppb_flash_file_module_local_impl_->RenameFile( | |
| 574 instance, from_path.c_str(), to_path.c_str()); | |
| 575 } | |
| 576 | |
| 577 void PPB_Flash_File_ModuleLocal_Proxy::OnMsgDeleteFileOrDir( | |
| 578 PP_Instance instance, | |
| 579 const std::string& path, | |
| 580 PP_Bool recursive, | |
| 581 int32_t* result) { | |
| 582 *result = ppb_flash_file_module_local_impl_->DeleteFileOrDir( | |
| 583 instance, path.c_str(), recursive); | |
| 584 } | |
| 585 | |
| 586 void PPB_Flash_File_ModuleLocal_Proxy::OnMsgCreateDir(PP_Instance instance, | |
| 587 const std::string& path, | |
| 588 int32_t* result) { | |
| 589 *result = ppb_flash_file_module_local_impl_->CreateDir( | |
| 590 instance, path.c_str()); | |
| 591 } | |
| 592 | |
| 593 void PPB_Flash_File_ModuleLocal_Proxy::OnMsgQueryFile(PP_Instance instance, | |
| 594 const std::string& path, | |
| 595 PP_FileInfo* info, | |
| 596 int32_t* result) { | |
| 597 *result = ppb_flash_file_module_local_impl_->QueryFile( | |
| 598 instance, path.c_str(), info); | |
| 599 } | |
| 600 | |
| 601 void PPB_Flash_File_ModuleLocal_Proxy::OnMsgGetDirContents( | |
| 602 PP_Instance instance, | |
| 603 const std::string& path, | |
| 604 std::vector<SerializedDirEntry>* entries, | |
| 605 int32_t* result) { | |
| 606 PP_DirContents_Dev* contents = NULL; | |
| 607 *result = ppb_flash_file_module_local_impl_->GetDirContents( | |
| 608 instance, path.c_str(), &contents); | |
| 609 if (*result != PP_OK) | |
| 610 return; | |
| 611 | |
| 612 // Convert the list of entries to the serialized version. | |
| 613 entries->resize(contents->count); | |
| 614 for (int32_t i = 0; i < contents->count; i++) { | |
| 615 (*entries)[i].name.assign(contents->entries[i].name); | |
| 616 (*entries)[i].is_dir = PP_ToBool(contents->entries[i].is_dir); | |
| 617 } | |
| 618 ppb_flash_file_module_local_impl_->FreeDirContents(instance, contents); | |
| 619 } | |
| 620 | |
| 621 // PPB_Flash_File_FileRef ------------------------------------------------------ | |
| 622 | |
| 623 namespace { | |
| 624 | |
| 625 int32_t OpenFileRefFile(PP_Resource file_ref_id, | |
| 626 int32_t mode, | |
| 627 PP_FileHandle* file) { | |
| 628 Resource* file_ref = | |
| 629 PpapiGlobals::Get()->GetResourceTracker()->GetResource(file_ref_id); | |
| 630 if (!file_ref) | |
| 631 return PP_ERROR_BADRESOURCE; | |
| 632 | |
| 633 PluginDispatcher* dispatcher = PluginDispatcher::GetForResource(file_ref); | |
| 634 if (!dispatcher) | |
| 635 return PP_ERROR_BADARGUMENT; | |
| 636 | |
| 637 int32_t result = PP_ERROR_FAILED; | |
| 638 IPC::PlatformFileForTransit transit; | |
| 639 dispatcher->Send(new PpapiHostMsg_PPBFlashFile_FileRef_OpenFile( | |
| 640 API_ID_PPB_FLASH_FILE_FILEREF, | |
| 641 file_ref->host_resource(), mode, &transit, &result)); | |
| 642 *file = IPC::PlatformFileForTransitToPlatformFile(transit); | |
| 643 return result; | |
| 644 } | |
| 645 | |
| 646 int32_t QueryFileRefFile(PP_Resource file_ref_id, | |
| 647 PP_FileInfo* info) { | |
| 648 Resource* file_ref = | |
| 649 PpapiGlobals::Get()->GetResourceTracker()->GetResource(file_ref_id); | |
| 650 if (!file_ref) | |
| 651 return PP_ERROR_BADRESOURCE; | |
| 652 | |
| 653 PluginDispatcher* dispatcher = PluginDispatcher::GetForResource(file_ref); | |
| 654 if (!dispatcher) | |
| 655 return PP_ERROR_BADARGUMENT; | |
| 656 | |
| 657 int32_t result = PP_ERROR_FAILED; | |
| 658 dispatcher->Send(new PpapiHostMsg_PPBFlashFile_FileRef_QueryFile( | |
| 659 API_ID_PPB_FLASH_FILE_FILEREF, | |
| 660 file_ref->host_resource(), info, &result)); | |
| 661 return result; | |
| 662 } | |
| 663 | |
| 664 const PPB_Flash_File_FileRef flash_file_fileref_interface = { | |
| 665 &OpenFileRefFile, | |
| 666 &QueryFileRefFile, | |
| 667 }; | |
| 668 | |
| 669 InterfaceProxy* CreateFlashFileFileRefProxy(Dispatcher* dispatcher) { | |
| 670 return new PPB_Flash_File_FileRef_Proxy(dispatcher); | |
| 671 } | |
| 672 | |
| 673 } // namespace | |
| 674 | |
| 675 PPB_Flash_File_FileRef_Proxy::PPB_Flash_File_FileRef_Proxy( | |
| 676 Dispatcher* dispatcher) | |
| 677 : InterfaceProxy(dispatcher), | |
| 678 ppb_flash_file_fileref_impl_(NULL) { | |
| 679 if (!dispatcher->IsPlugin()) { | |
| 680 ppb_flash_file_fileref_impl_ = static_cast<const PPB_Flash_File_FileRef*>( | |
| 681 dispatcher->local_get_interface()(PPB_FLASH_FILE_FILEREF_INTERFACE)); | |
| 682 } | |
| 683 } | |
| 684 | |
| 685 PPB_Flash_File_FileRef_Proxy::~PPB_Flash_File_FileRef_Proxy() { | |
| 686 } | |
| 687 | |
| 688 // static | |
| 689 const PPB_Flash_File_FileRef* PPB_Flash_File_FileRef_Proxy::GetInterface() { | |
| 690 return &flash_file_fileref_interface; | |
| 691 } | |
| 692 | |
| 693 bool PPB_Flash_File_FileRef_Proxy::OnMessageReceived( | |
| 694 const IPC::Message& msg) { | |
| 695 bool handled = true; | |
| 696 IPC_BEGIN_MESSAGE_MAP(PPB_Flash_File_FileRef_Proxy, msg) | |
| 697 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBFlashFile_FileRef_OpenFile, | |
| 698 OnMsgOpenFile) | |
| 699 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBFlashFile_FileRef_QueryFile, | |
| 700 OnMsgQueryFile) | |
| 701 IPC_MESSAGE_UNHANDLED(handled = false) | |
| 702 IPC_END_MESSAGE_MAP() | |
| 703 // TODO(brettw) handle bad messages! | |
| 704 return handled; | |
| 705 } | |
| 706 | |
| 707 void PPB_Flash_File_FileRef_Proxy::OnMsgOpenFile( | |
| 708 const HostResource& host_resource, | |
| 709 int32_t mode, | |
| 710 IPC::PlatformFileForTransit* file_handle, | |
| 711 int32_t* result) { | |
| 712 base::PlatformFile file; | |
| 713 *result = ppb_flash_file_fileref_impl_->OpenFile( | |
| 714 host_resource.host_resource(), mode, &file); | |
| 715 *file_handle = PlatformFileToPlatformFileForTransit( | |
| 716 dispatcher(), result, file); | |
| 717 } | |
| 718 | |
| 719 void PPB_Flash_File_FileRef_Proxy::OnMsgQueryFile( | |
| 720 const HostResource& host_resource, | |
| 721 PP_FileInfo* info, | |
| 722 int32_t* result) { | |
| 723 *result = ppb_flash_file_fileref_impl_->QueryFile( | |
| 724 host_resource.host_resource(), info); | |
| 725 } | |
| 726 | |
| 727 } // namespace proxy | |
| 728 } // namespace ppapi | |
| OLD | NEW |