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 |