Index: content/browser/renderer_host/pepper/pepper_filesystem_provider_backend_chromeos.cc |
diff --git a/content/browser/renderer_host/pepper/pepper_filesystem_provider_backend_chromeos.cc b/content/browser/renderer_host/pepper/pepper_filesystem_provider_backend_chromeos.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..42fc8eb087299c64a2251ee0ce1d210cb959cad5 |
--- /dev/null |
+++ b/content/browser/renderer_host/pepper/pepper_filesystem_provider_backend_chromeos.cc |
@@ -0,0 +1,779 @@ |
+// Copyright 2015 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "content/browser/renderer_host/pepper/pepper_filesystem_provider_backend_chromeos.h" |
+ |
+#include <chrono> |
+ |
+#include "base/memory/shared_memory.h" |
+#include "chrome/browser/chromeos/file_system_provider/provided_file_system_info.h" |
+#include "chrome/browser/chromeos/file_system_provider/request_manager.h" |
+#include "chrome/browser/chromeos/file_system_provider/file_system_plugin/plugin_service.h" |
+#include "chrome/browser/profiles/profile_manager.h" |
+#include "content/public/browser/browser_ppapi_host.h" |
+#include "content/public/browser/browser_thread.h" |
+#include "ppapi/c/pp_errors.h" |
+#include "ppapi/host/ppapi_host.h" |
+#include "ppapi/proxy/ppapi_messages.h" |
+ |
+using namespace chromeos::file_system_provider; |
+using content::BrowserThread; |
+using ppapi::host::HostMessageContext; |
+ |
+namespace content { |
+ |
+namespace { |
+ |
+// TODO(sabin): find a way to get the size of the stream reader internal |
+// buffer from the backend |
+// Size of the stream reader internal buffer. At most this number of bytes will |
+// be read ahead of the requested data. |
+const uint32_t kReaderBufferSize = 512 * 1024; // 512KB. |
+ |
+// Size of the stream writer internal buffer. At most this number of bytes will |
+// be postponed for writing. |
+const uint32_t kWriterBufferSize = 512 * 1024; // 512KB. |
+ |
+// The number of requests that can be buffered |
+const uint32_t kMaximumCachedReplies = 10; |
+ |
+RequestType PP_OperationToRequestType(int32_t operation_type) { |
+ switch (operation_type) { |
+ case PP_OperationType_ABORT: |
+ return ABORT; |
+ case PP_OperationType_ADDWATCHER: |
+ return ADD_WATCHER; |
+ case PP_OperationType_CLOSEFILE: |
+ return CLOSE_FILE; |
+ case PP_OperationType_COPYENTRY: |
+ return COPY_ENTRY; |
+ case PP_OperationType_CREATEDIRECTORY: |
+ return CREATE_DIRECTORY; |
+ case PP_OperationType_CREATEFILE: |
+ return CREATE_FILE; |
+ case PP_OperationType_DELETEENTRY: |
+ return DELETE_ENTRY; |
+ case PP_OperationType_GETMETADATA: |
+ return GET_METADATA; |
+ case PP_OperationType_MOVEENTRY: |
+ return MOVE_ENTRY; |
+ case PP_OperationType_OPENFILE: |
+ return OPEN_FILE; |
+ case PP_OperationType_READDIRECTORY: |
+ return READ_DIRECTORY; |
+ case PP_OperationType_READFILE: |
+ return READ_FILE; |
+ case PP_OperationType_REMOVEWATCHER: |
+ return REMOVE_WATCHER; |
+ case PP_OperationType_TRUNCATEENTRY: |
+ return TRUNCATE; |
+ case PP_OperationType_UNMOUNT: |
+ return REQUEST_UNMOUNT; |
+ case PP_OperationType_WRITEFILE: |
+ return WRITE_FILE; |
+ case PP_OperationType_NONE: |
+ default: |
+ break; |
+ } |
+ NOTREACHED(); |
+ return ABORT; |
+} |
+ |
+PP_OperationType_Dev RequestTypeToOperationType(int32_t operation_type) { |
+ switch (operation_type) { |
+ case ABORT: |
+ return PP_OperationType_ABORT; |
+ case ADD_WATCHER: |
+ return PP_OperationType_ADDWATCHER; |
+ case CLOSE_FILE: |
+ return PP_OperationType_CLOSEFILE; |
+ case COPY_ENTRY: |
+ return PP_OperationType_COPYENTRY; |
+ case CREATE_DIRECTORY: |
+ return PP_OperationType_CREATEDIRECTORY; |
+ case CREATE_FILE: |
+ return PP_OperationType_CREATEFILE; |
+ case DELETE_ENTRY: |
+ return PP_OperationType_DELETEENTRY; |
+ case GET_METADATA: |
+ return PP_OperationType_GETMETADATA; |
+ case MOVE_ENTRY: |
+ return PP_OperationType_MOVEENTRY; |
+ case OPEN_FILE: |
+ return PP_OperationType_OPENFILE; |
+ case READ_DIRECTORY: |
+ return PP_OperationType_READDIRECTORY; |
+ case READ_FILE: |
+ return PP_OperationType_READFILE; |
+ case REMOVE_WATCHER: |
+ return PP_OperationType_REMOVEWATCHER; |
+ case TRUNCATE: |
+ return PP_OperationType_TRUNCATEENTRY; |
+ case REQUEST_UNMOUNT: |
+ return PP_OperationType_UNMOUNT; |
+ case WRITE_FILE: |
+ return PP_OperationType_WRITEFILE; |
+ default: |
+ break; |
+ } |
+ NOTREACHED(); |
+ return PP_OperationType_NONE; |
+} |
+ |
+} // namespace |
+ |
+PepperFilesystemProviderBackendChromeOS:: |
+ ProvidedFilesystemInfo::ProvidedFilesystemInfo() |
+ :filesystem_id("none"), |
+ display_name("none"), |
+ plugin_name("none"), |
+ writable(false), |
+ opened_files_limit(0) { |
+} |
+PepperFilesystemProviderBackendChromeOS::ShmBuffer::ShmBuffer( |
+ uint32_t size, scoped_ptr<base::SharedMemory> shm) |
+ : size(size),shm(shm.Pass()) { |
+ DCHECK(this->shm); |
+} |
+ |
+PepperFilesystemProviderBackendChromeOS::ShmBuffer::~ShmBuffer() { |
+ |
+} |
+ |
+PepperFilesystemProviderBackendChromeOS:: |
+ ShmChannelController::ShmChannelController( |
+ uint32_t size, FlushRequestCallback callback) |
+ : max_size(size), |
+ ready(true), |
+ callback(callback){ |
+} |
+PepperFilesystemProviderBackendChromeOS:: |
+ ShmChannelController::~ShmChannelController() { |
+} |
+ |
+bool PepperFilesystemProviderBackendChromeOS:: |
+ ShmChannelController::EnqueueRequest( |
+ scoped_ptr<base::ListValue> response) { |
+ // If channel ready send it straight away |
+ if(ready) { |
+ ready = !callback.Run(response.Pass()); |
+ if(!ready) |
+ return true; |
+ } |
+ // If channel is not ready or failed to send |
+ // cache the request |
+ if(size() + 1 > max_size) |
+ return false; |
+ replies.push_back( response.Pass() ); |
+ return true; |
+} |
+ |
+bool PepperFilesystemProviderBackendChromeOS:: |
+ ShmChannelController::PushNextRequest() { |
+ // Try and send the request |
+ scoped_ptr<base::ListValue> response; |
+ while (size()>0 && ready ) { |
+ response.reset(replies.front()); |
+ replies.weak_erase(replies.begin()); |
+ ready = !callback.Run(response.Pass()); |
+ } |
+ return !ready; |
+} |
+ |
+bool |
+PepperFilesystemProviderBackendChromeOS:: |
+ ShmChannelController::AckLastPushedRequest() { |
+ return ready = true; |
+} |
+ |
+uint32_t PepperFilesystemProviderBackendChromeOS:: |
+ ShmChannelController::size() { |
+ return replies.size(); |
+} |
+ |
+ |
+ |
+PepperFilesystemProviderBackendChromeOS:: |
+PepperFilesystemProviderBackendChromeOS( |
+ content::BrowserPpapiHost *host, |
+ PP_Instance instance, |
+ PP_Resource resource) |
+ : mounted_(false), |
+ host_(host ? host->GetPpapiHost() : nullptr), |
+ resource_(resource), |
+ write_channel_controller_(new ShmChannelController( |
+ kMaximumCachedReplies, |
+ base::Bind( |
+ &PepperFilesystemProviderBackendChromeOS:: |
+ FlushRequest, |
+ base::Unretained(this)))), |
+ weak_factory_(this) { |
+ |
+ filesystem_info_.plugin_name = std::string("Plugin_") + |
+ std::to_string(static_cast<size_t>(instance)); |
+} |
+ |
+PepperFilesystemProviderBackendChromeOS:: |
+~PepperFilesystemProviderBackendChromeOS() { |
+ // Unregister the filesystem if state indicates |
+ // that we have a mounted filesystem |
+ if (mounted_) { |
+ // Unregister any registered event from the PluginEventRouter |
+ UnregisterFilesystemListenedOperations(); |
+ // Unregister the filesystem backend on the |
+ // proper thread from Service |
+ BrowserThread::PostTask( |
+ BrowserThread::UI, |
+ FROM_HERE, |
+ base::Bind( |
+ base::IgnoreResult( |
+ &PepperFilesystemProviderBackendChromeOS:: |
+ UnregisterFilesystemOnUI), |
+ filesystem_info_ |
+ ) |
+ ); |
+ } |
+} |
+ |
+// Called when PpapiHostMsg_FilesystemProvider_Mount is received |
+// Forwards request to RegisterFilesystemOnUI |
+// Response is sent from MountReplyOnIO |
+int32_t PepperFilesystemProviderBackendChromeOS::SendMountRequest( |
+ ppapi::host::HostMessageContext *context, |
+ const base::ListValue& request) { |
+ using content::filesystem_provider_internal::MountOperationTranslator; |
+ |
+ base::File::Error status = base::File::FILE_OK; |
+ if (mounted_) |
+ status = base::File::FILE_ERROR_EXISTS; |
+ |
+ scoped_ptr<MountOperationTranslator> mount_info = |
+ MountOperationTranslator::PopulateFromResponse(request); |
+ if ( !mount_info.get() ) |
+ status = base::File::FILE_ERROR_FAILED; |
+ |
+ // Stop and send failure back to the plugin |
+ if (status!=base::File::FILE_OK) { |
+ MountReplyOnIO( |
+ context->MakeReplyMessageContext(), |
+ filesystem_info_, base::File::FILE_ERROR_EXISTS); |
+ return PP_OK_COMPLETIONPENDING; |
+ } |
+ // Populate the desired filesystem configuration |
+ ProvidedFilesystemInfo filesystem_info; |
+ filesystem_info.writable = mount_info->writable; |
+ filesystem_info.display_name = mount_info->display_name; |
+ filesystem_info.plugin_name = filesystem_info_.plugin_name; |
+ filesystem_info.filesystem_id = mount_info->file_system_id; |
+ filesystem_info.opened_files_limit = mount_info->opened_files_limit; |
+ // Change thread to create the filesystem backend on the |
+ // UI thread. The result of this action is to be interpreted |
+ // on the IO thread. |
+ BrowserThread::PostTaskAndReplyWithResult( |
+ BrowserThread::UI, |
+ FROM_HERE, |
+ base::Bind( |
+ // This creates a filesystem backend owned by the Service |
+ // entity |
+ &PepperFilesystemProviderBackendChromeOS::RegisterFilesystemOnUI, |
+ filesystem_info), |
+ // This is called after the above returns to interpret result |
+ base::Bind( |
+ &PepperFilesystemProviderBackendChromeOS::MountReplyOnIO, |
+ weak_factory_.GetWeakPtr(), |
+ context->MakeReplyMessageContext(), |
+ filesystem_info |
+ ) |
+ ); |
+ return PP_OK_COMPLETIONPENDING; |
+} |
+ |
+// Called when PpapiHostMsg_FilesystemProvider_Unmount is received |
+// Forwards request to UnregisterFilesystemOnUI |
+// Response is sent from MountReplyOnIO |
+int32_t PepperFilesystemProviderBackendChromeOS::SendUnmountRequest( |
+ ppapi::host::HostMessageContext *context, const std::string& fsid) { |
+ |
+ if(!mounted_) { |
+ return PP_ERROR_FAILED; |
+ } |
+ |
+ // Remove registered events from PluginEventRouter |
+ UnregisterFilesystemListenedOperations(); |
+ |
+ BrowserThread::PostTaskAndReplyWithResult( |
+ BrowserThread::UI, |
+ FROM_HERE, |
+ base::Bind( |
+ &PepperFilesystemProviderBackendChromeOS::UnregisterFilesystemOnUI, |
+ filesystem_info_), |
+ base::Bind( &PepperFilesystemProviderBackendChromeOS::UnmountReplyOnIO, |
+ weak_factory_.GetWeakPtr(), |
+ context->MakeReplyMessageContext()) |
+ ); |
+ return PP_OK_COMPLETIONPENDING; |
+} |
+ |
+int32_t PepperFilesystemProviderBackendChromeOS::OnPluginResponse( |
+ ppapi::host::HostMessageContext* context, |
+ const base::ListValue& plugin_response) { |
+ scoped_ptr<base::ListValue> response( plugin_response.DeepCopy() ); |
+ |
+ if (!response.get() || |
+ !mounted_) |
+ return PP_ERROR_FAILED; |
+ |
+ bool status; |
+ int operation_type = PP_OperationType_NONE; |
+ if (!PreprocessMessage(*response, status, operation_type)) |
+ return PP_ERROR_FAILED; |
+ if ( status ) {// success |
+ BrowserThread::PostTask( |
+ BrowserThread::UI, |
+ FROM_HERE, |
+ base::Bind( |
+ base::IgnoreResult( |
+ &PepperFilesystemProviderBackendChromeOS:: |
+ OnSuccessResponse), |
+ operation_type, |
+ filesystem_info_, |
+ base::Passed(response.Pass())) |
+ ); |
+ } else { // failure |
+ BrowserThread::PostTask( |
+ BrowserThread::UI, |
+ FROM_HERE, |
+ base::Bind( |
+ base::IgnoreResult( |
+ &PepperFilesystemProviderBackendChromeOS:: |
+ OnErrorResponse), |
+ filesystem_info_, |
+ base::Passed(response.Pass())) |
+ ); |
+ } |
+ |
+ return PP_OK; |
+} |
+ |
+// Sends next cached request if there is any pending |
+int32_t PepperFilesystemProviderBackendChromeOS::OnPluginWriteAck( |
+ ppapi::host::HostMessageContext* ) { |
+ write_channel_controller_->AckLastPushedRequest(); |
+ write_channel_controller_->PushNextRequest(); |
+ return PP_OK; |
+} |
+ |
+int32_t PepperFilesystemProviderBackendChromeOS::OnPluginNotification( |
+ ppapi::host::HostMessageContext* context, const base::ListValue& args) { |
+ scoped_ptr<base::ListValue> message(args.DeepCopy()); |
+ BrowserThread::PostTask( |
+ BrowserThread::UI, |
+ FROM_HERE, |
+ base::Bind( |
+ &PepperFilesystemProviderBackendChromeOS:: |
+ SendNotificationOnUI, |
+ filesystem_info_, base::Passed(message.Pass()) |
+ ) |
+ ); |
+ return PP_OK; |
+} |
+ |
+void OnNotifyCompleted(base::File::Error /*result*/) {} |
+ |
+void PepperFilesystemProviderBackendChromeOS::SendNotificationOnUI( |
+ const ProvidedFilesystemInfo& file_system_info, |
+ scoped_ptr<base::ListValue> args) { |
+ DCHECK_CURRENTLY_ON(BrowserThread::UI); |
+ |
+ PluginService *fs_service = PluginService::Get( |
+ ProfileManager::GetActiveUserProfile()); |
+ DCHECK(fs_service); |
+ |
+ ProvidedFileSystemAdapter* fs_backend = |
+ fs_service->GetProvidedFileSystemAdapter( |
+ file_system_info.plugin_name, |
+ file_system_info.filesystem_id); |
+ if (!fs_backend) |
+ return; |
+ fs_backend->PushChangeNotificationResponse(args.Pass(), |
+ base::Bind(OnNotifyCompleted)); |
+} |
+ |
+// Add all events to the PluginEventRouter list of dispatchable events |
+void PepperFilesystemProviderBackendChromeOS:: |
+RegisterFilesystemListenedOperations() { |
+ DCHECK_CURRENTLY_ON(BrowserThread::IO); |
+ std::vector<RequestType> operations = { |
+ REQUEST_UNMOUNT, GET_METADATA, READ_DIRECTORY, OPEN_FILE, CLOSE_FILE, |
+ READ_FILE, CREATE_DIRECTORY, DELETE_ENTRY, CREATE_FILE, COPY_ENTRY, |
+ MOVE_ENTRY, TRUNCATE, WRITE_FILE, ABORT, ADD_WATCHER, REMOVE_WATCHER |
+ }; |
+ PluginOperationRouter *router = PluginOperationRouter::GetInstance(); |
+ if (router!=nullptr) |
+ router->AddOperationsForListener( operations, this, |
+ filesystem_info_.plugin_name ); |
+} |
+using chromeos::file_system_provider::READ_DIRECTORY; |
+// Remove all events from the PluginEventRouter list of dispatchable events |
+void PepperFilesystemProviderBackendChromeOS:: |
+UnregisterFilesystemListenedOperations() { |
+ DCHECK_CURRENTLY_ON(BrowserThread::IO); |
+ std::vector<RequestType> operations = { |
+ REQUEST_UNMOUNT, GET_METADATA, READ_DIRECTORY, OPEN_FILE, CLOSE_FILE, |
+ READ_FILE, CREATE_DIRECTORY, DELETE_ENTRY, CREATE_FILE, COPY_ENTRY, |
+ MOVE_ENTRY, TRUNCATE, WRITE_FILE, ABORT, ADD_WATCHER, REMOVE_WATCHER |
+ }; |
+ PluginOperationRouter *router = PluginOperationRouter::GetInstance(); |
+ if (router!=nullptr) |
+ router->RemoveOperationsForListener(operations, |
+ filesystem_info_.plugin_name); |
+} |
+ |
+// Static |
+// Responsible with the creations and registration of a new provided filesystem |
+base::File::Error PepperFilesystemProviderBackendChromeOS:: |
+RegisterFilesystemOnUI( |
+ ProvidedFilesystemInfo filesystem_info) |
+{ |
+ DCHECK_CURRENTLY_ON(BrowserThread::UI); |
+ |
+ PluginService *fs_service = PluginService::Get( |
+ ProfileManager::GetActiveUserProfile()); |
+ DCHECK(fs_service); |
+ |
+ chromeos::file_system_provider::MountOptions options( |
+ filesystem_info.filesystem_id, filesystem_info.display_name); |
+ |
+ // TODO(sabin): add support for watchers |
+ options.supports_notify_tag = false; |
+ options.writable = filesystem_info.writable; |
+ options.opened_files_limit = filesystem_info.opened_files_limit; |
+ |
+ base::File::Error error = fs_service->MountFileSystem( |
+ filesystem_info.plugin_name, |
+ options); |
+ |
+ return error; // This will be interpreted by MountReplyOnIO |
+} |
+ |
+// Sends feedback to the plugin |
+// and sets state |
+void PepperFilesystemProviderBackendChromeOS::MountReplyOnIO( |
+ ppapi::host::ReplyMessageContext reply_msg, |
+ ProvidedFilesystemInfo filesystem_info, |
+ base::File::Error err) { |
+ DCHECK_CURRENTLY_ON(BrowserThread::IO); |
+ |
+ // If an error occured or we cannot initialize the shared memory |
+ if ( err != base::File::FILE_OK || |
+ !InitializeMemoryBuffer()) { |
+ reply_msg.params.set_result(PP_ERROR_FAILED); |
+ host_->SendReply( |
+ reply_msg, |
+ PpapiPluginMsg_FilesystemProvider_MountReply() |
+ ); |
+ // Undo the registration |
+ if (err==base::File::FILE_OK) { |
+ BrowserThread::PostTask( |
+ BrowserThread::UI, |
+ FROM_HERE, |
+ base::Bind( |
+ base::IgnoreResult( |
+ &PepperFilesystemProviderBackendChromeOS:: |
+ UnregisterFilesystemOnUI), |
+ filesystem_info |
+ ) |
+ ); |
+ } |
+ return; |
+ } |
+ |
+ RegisterFilesystemListenedOperations(); |
+ mounted_ = true; |
+ filesystem_info_.writable = filesystem_info.writable; |
+ filesystem_info_.display_name = filesystem_info.display_name; |
+ filesystem_info_.filesystem_id = filesystem_info.filesystem_id; |
+ filesystem_info_.opened_files_limit = filesystem_info.opened_files_limit; |
+ |
+ |
+ reply_msg.params.set_result(PP_OK); |
+ host_->SendReply( |
+ reply_msg, |
+ PpapiPluginMsg_FilesystemProvider_MountReply() |
+ ); |
+} |
+ |
+//static |
+// Responsible with removal of the filesystem backend |
+base::File::Error PepperFilesystemProviderBackendChromeOS:: |
+UnregisterFilesystemOnUI( |
+ ProvidedFilesystemInfo filesystem_info) { |
+ DCHECK_CURRENTLY_ON(BrowserThread::UI); |
+ |
+ PluginService *fs_service = PluginService::Get( |
+ ProfileManager::GetActiveUserProfile()); |
+ DCHECK(fs_service); |
+ |
+ base::File::Error err = fs_service->UnmountFileSystem( |
+ filesystem_info.plugin_name, |
+ filesystem_info.filesystem_id, |
+ chromeos::file_system_provider::PluginService::UNMOUNT_REASON_USER ); |
+ |
+ return err; |
+} |
+ |
+// Sends feedback to the plugin |
+// and resets state |
+void PepperFilesystemProviderBackendChromeOS::UnmountReplyOnIO( |
+ ppapi::host::ReplyMessageContext reply_msg, base::File::Error err) { |
+ |
+ reply_msg.params.set_result(PP_OK); |
+ // Unregister all events |
+ UnregisterFilesystemListenedOperations(); |
+ |
+ mounted_ = false; |
+ // Send result to the plugin |
+ host_->SendReply( |
+ reply_msg, |
+ PpapiPluginMsg_FilesystemProvider_UnmountReply() |
+ ); |
+} |
+ |
+void PepperFilesystemProviderBackendChromeOS::OnDispatchOperationRequest( |
+ RequestType operation_type, scoped_ptr<base::ListValue> request) { |
+ if ( operation_type==WRITE_FILE ) { |
+ // Handle write to filesystem |
+ // Put the chunk into the shared memory buffer or cache it |
+ // if channel is not free |
+ // TODO(sabin): Send error back to backend if this fails |
+ write_channel_controller_->EnqueueRequest(request.Pass()); |
+ } else { |
+ //TODO(sabin): Remove this when done testing |
+ if(operation_type==OPEN_FILE) |
+ time_stamp_=std::chrono::system_clock::now(); |
+ else if(operation_type==CLOSE_FILE) { |
+ std::chrono::duration<double> elapsed_seconds = |
+ std::chrono::system_clock::now()-time_stamp_; |
+ LOG(ERROR) <<"Read/Write operation time: "<< elapsed_seconds.count()<< |
+ " seconds"; |
+ } |
+ host_->SendUnsolicitedReply( |
+ resource_, |
+ PpapiPluginMsg_FilesystemProvider_OperationRequest( |
+ RequestTypeToOperationType(operation_type), |
+ *request) |
+ ); |
+ } |
+} |
+ |
+// Transforms messages that are received from |
+// the plugin in response of filesystem operations and sends |
+// them back to the filesystem backend. |
+int32_t PepperFilesystemProviderBackendChromeOS::OnSuccessResponse( |
+ int operation, |
+ const ProvidedFilesystemInfo& filesystem_info, |
+ scoped_ptr<base::ListValue> response ) { |
+ |
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
+ PluginService *fs_service = PluginService::Get( |
+ ProfileManager::GetActiveUserProfile()); |
+ DCHECK(fs_service); |
+ |
+ ProvidedFileSystemAdapter* fs_backend = |
+ fs_service->GetProvidedFileSystemAdapter( |
+ filesystem_info.plugin_name, |
+ filesystem_info.filesystem_id); |
+ |
+ if (fs_backend==nullptr) |
+ return PP_ERROR_FAILED; |
+ fs_backend->PushSuccessResponse( PP_OperationToRequestType(operation), |
+ response.Pass()); |
+ |
+ return PP_OK; |
+} |
+ |
+int32_t PepperFilesystemProviderBackendChromeOS::OnErrorResponse( |
+ const ProvidedFilesystemInfo& filesystem_info, |
+ scoped_ptr<base::ListValue> response) { |
+ |
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
+ |
+ PluginService *fs_service = PluginService::Get( |
+ ProfileManager::GetActiveUserProfile()); |
+ DCHECK(fs_service); |
+ |
+ ProvidedFileSystemAdapter* fs_backend = |
+ fs_service->GetProvidedFileSystemAdapter( |
+ filesystem_info.plugin_name, |
+ filesystem_info.filesystem_id); |
+ if(fs_backend==nullptr) |
+ return PP_ERROR_FAILED; |
+ fs_backend->PushErrorResponse(response.Pass()); |
+ return PP_OK; |
+} |
+ |
+bool PepperFilesystemProviderBackendChromeOS::FlushRequest( |
+ scoped_ptr<base::ListValue> request) { |
+ if(!request.get()) |
+ return false; |
+ |
+ if(!AddFromMessageToSharedMemory(*request)) |
+ return false; |
+ |
+ host_->SendUnsolicitedReply( |
+ resource_, |
+ PpapiPluginMsg_FilesystemProvider_OperationRequest( |
+ PP_OperationType_WRITEFILE, |
+ *request)); |
+ return true; |
+} |
+bool PepperFilesystemProviderBackendChromeOS::InitializeMemoryBuffer() { |
+ // Already initialized |
+ if(read_write_buffer_.get()) |
+ return true; |
+ scoped_ptr<base::SharedMemory> buffer( new base::SharedMemory ); |
+ size_t size = kReaderBufferSize + kWriterBufferSize; |
+ if (!buffer.get() || |
+ !buffer->CreateAndMapAnonymous(size)) |
+ return false; |
+ read_write_buffer_=make_scoped_ptr(new ShmBuffer(size, buffer.Pass())); |
+ if(!read_write_buffer_.get()) |
+ return false; |
+ using ppapi::proxy::SerializedHandle; |
+ std::vector<SerializedHandle> handles; |
+ handles.push_back( |
+ SerializedHandle(read_write_buffer_->shm->handle(), size )); |
+ // Send a message to the plugin with the shared mem handle |
+ host_->SendUnsolicitedReplyWithHandles( |
+ resource_, |
+ PpapiPluginMsg_FilesystemProvider_Buffers( |
+ kReaderBufferSize, |
+ kWriterBufferSize), |
+ handles |
+ ); |
+ return true; |
+} |
+bool PepperFilesystemProviderBackendChromeOS::AddFromSharedMemoryToMessage( |
+ base::ListValue& message) { |
+ DCHECK(read_write_buffer_.get()); |
+ double out = 0; |
+ if(!message.GetDouble(2,&out)) |
+ return false; |
+ size_t out_size = out; |
+ if(out_size>kReaderBufferSize) |
+ return false; |
+ |
+ // Replace the size with the actual data |
+ bool status = message.Set(2, base::BinaryValue::CreateWithCopiedBuffer( |
+ (const char*)read_write_buffer_->shm->memory(), out_size)); |
+ SendReadAck(); |
+ return status; |
+} |
+bool PepperFilesystemProviderBackendChromeOS::AddFromMessageToSharedMemory( |
+ base::ListValue& message) { |
+ if( !read_write_buffer_.get() ) |
+ return false; |
+ |
+ base::Value *dict_value = nullptr; |
+ if(!message.Get(0,&dict_value)) |
+ return false; |
+ |
+ base::DictionaryValue* dict = |
+ static_cast<base::DictionaryValue*>(dict_value); |
+ const base::BinaryValue* binary_value = NULL; |
+ if (!dict->GetBinary("data", &binary_value)) |
+ return false; |
+ // This can be '0' |
+ size_t binary_size =binary_value->GetSize(); |
+ // Skip the read buffer and copy to shared mem the buffer into |
+ // the write portion of the buffer |
+ if(binary_size>kWriterBufferSize) |
+ return false; |
+ memcpy( (char*)read_write_buffer_->shm->memory()+kReaderBufferSize, |
+ binary_value->GetBuffer(), |
+ binary_size); |
+ dict->Remove( "data", nullptr ); |
+ dict->SetDouble( "size",binary_size); |
+ return true; |
+} |
+bool PepperFilesystemProviderBackendChromeOS::PreprocessMessage( |
+ base::ListValue& message, |
+ bool& message_status, |
+ int& operation_type) { |
+ // Remove the custom "header" from the response |
+ scoped_ptr<base::Value> operation_value = nullptr; |
+ if (!message.Remove(0,&operation_value)) |
+ return false; |
+ if (!operation_value->GetAsInteger(&operation_type)) |
+ return false; |
+ // Get the status of the operation |
+ scoped_ptr<base::Value> status_value=nullptr; |
+ if (!message.Remove(0,&status_value)) |
+ return false; |
+ if (!status_value->GetAsBoolean(&message_status)) |
+ return false; |
+ switch (operation_type) { |
+ case PP_OperationType_READFILE: |
+ if (!AddFromSharedMemoryToMessage(message)) |
+ return false; |
+ break; |
+ case PP_OperationType_UNMOUNT: |
+ if ( message_status ) |
+ mounted_ = false; |
+ break; |
+ default: |
+ break; |
+ } |
+ return true; |
+} |
+ |
+void PepperFilesystemProviderBackendChromeOS::SendReadAck() { |
+ // ACK the receipt and let the plugin know that if it has more |
+ // requests it can send them |
+ if (host_) |
+ host_->SendUnsolicitedReply(resource_, |
+ PpapiPluginMsg_FilesystemProvider_ReadAck()); |
+} |
+ |
+namespace filesystem_provider_internal { |
+scoped_ptr<MountOperationTranslator> |
+ MountOperationTranslator::PopulateFromResponse( |
+ const base::ListValue& request) { |
+ const base::Value *dict_value = nullptr; |
+ if(!request.Get(0,&dict_value)) |
+ return scoped_ptr<MountOperationTranslator>(); |
+ |
+ const base::DictionaryValue* dict = |
+ static_cast<const base::DictionaryValue*>(dict_value); |
+ |
+ scoped_ptr< MountOperationTranslator > out(new MountOperationTranslator); |
+ |
+ const base::Value* data_value = nullptr; |
+ if (!dict->GetWithoutPathExpansion("fileSystemId", &data_value) || |
+ !data_value->IsType(base::Value::TYPE_STRING)) |
+ return scoped_ptr<MountOperationTranslator>(); |
+ if (!data_value->GetAsString(&out->file_system_id)) |
+ return scoped_ptr<MountOperationTranslator>(); |
+ if (!dict->GetWithoutPathExpansion("displayName", &data_value) || |
+ !data_value->IsType(base::Value::TYPE_STRING)) |
+ return scoped_ptr<MountOperationTranslator>(); |
+ if (!data_value->GetAsString(&out->display_name)) |
+ return scoped_ptr<MountOperationTranslator>(); |
+ if (!dict->GetWithoutPathExpansion("writable", &data_value) || |
+ !data_value->IsType(base::Value::TYPE_BOOLEAN)) |
+ return scoped_ptr<MountOperationTranslator>(); |
+ if (!data_value->GetAsBoolean(&out->writable)) |
+ return scoped_ptr<MountOperationTranslator>(); |
+ |
+ if (!dict->GetWithoutPathExpansion("openedFilesLimit", &data_value) || |
+ !data_value->IsType(base::Value::TYPE_INTEGER)) |
+ return scoped_ptr<MountOperationTranslator>(); |
+ if (!data_value->GetAsInteger(&out->opened_files_limit)) |
+ return scoped_ptr<MountOperationTranslator>(); |
+ |
+ return out.Pass(); |
+} |
+} // namespace filesystem_provider_internal |
+} // namespace content |
+ |