// Copyright (c) 2012 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/child/fileapi/file_system_dispatcher.h" #include "base/callback.h" #include "base/files/file_util.h" #include "base/message_loop/message_loop_proxy.h" #include "base/process/process.h" #include "content/child/child_thread_impl.h" #include "content/common/fileapi/file_system_messages.h" #include "storage/common/fileapi/file_system_info.h" namespace content { class FileSystemDispatcher::CallbackDispatcher { public: typedef CallbackDispatcher self; typedef FileSystemDispatcher::StatusCallback StatusCallback; typedef FileSystemDispatcher::MetadataCallback MetadataCallback; typedef FileSystemDispatcher::ReadDirectoryCallback ReadDirectoryCallback; typedef FileSystemDispatcher::OpenFileSystemCallback OpenFileSystemCallback; typedef FileSystemDispatcher::ResolveURLCallback ResolveURLCallback; typedef FileSystemDispatcher::WriteCallback WriteCallback; typedef FileSystemDispatcher::OpenFileCallback OpenFileCallback; static CallbackDispatcher* Create(const StatusCallback& callback) { CallbackDispatcher* dispatcher = new CallbackDispatcher; dispatcher->status_callback_ = callback; dispatcher->error_callback_ = callback; return dispatcher; } static CallbackDispatcher* Create(const MetadataCallback& callback, const StatusCallback& error_callback) { CallbackDispatcher* dispatcher = new CallbackDispatcher; dispatcher->metadata_callback_ = callback; dispatcher->error_callback_ = error_callback; return dispatcher; } static CallbackDispatcher* Create(const CreateSnapshotFileCallback& callback, const StatusCallback& error_callback) { CallbackDispatcher* dispatcher = new CallbackDispatcher; dispatcher->snapshot_callback_ = callback; dispatcher->error_callback_ = error_callback; return dispatcher; } static CallbackDispatcher* Create(const ReadDirectoryCallback& callback, const StatusCallback& error_callback) { CallbackDispatcher* dispatcher = new CallbackDispatcher; dispatcher->directory_callback_ = callback; dispatcher->error_callback_ = error_callback; return dispatcher; } static CallbackDispatcher* Create(const OpenFileSystemCallback& callback, const StatusCallback& error_callback) { CallbackDispatcher* dispatcher = new CallbackDispatcher; dispatcher->filesystem_callback_ = callback; dispatcher->error_callback_ = error_callback; return dispatcher; } static CallbackDispatcher* Create(const ResolveURLCallback& callback, const StatusCallback& error_callback) { CallbackDispatcher* dispatcher = new CallbackDispatcher; dispatcher->resolve_callback_ = callback; dispatcher->error_callback_ = error_callback; return dispatcher; } static CallbackDispatcher* Create(const WriteCallback& callback, const StatusCallback& error_callback) { CallbackDispatcher* dispatcher = new CallbackDispatcher; dispatcher->write_callback_ = callback; dispatcher->error_callback_ = error_callback; return dispatcher; } ~CallbackDispatcher() {} void DidSucceed() { status_callback_.Run(base::File::FILE_OK); } void DidFail(base::File::Error error_code) { error_callback_.Run(error_code); } void DidReadMetadata( const base::File::Info& file_info) { metadata_callback_.Run(file_info); } void DidCreateSnapshotFile( const base::File::Info& file_info, const base::FilePath& platform_path, int request_id) { snapshot_callback_.Run(file_info, platform_path, request_id); } void DidReadDirectory(const std::vector& entries, bool has_more) { directory_callback_.Run(entries, has_more); } void DidOpenFileSystem(const std::string& name, const GURL& root) { filesystem_callback_.Run(name, root); } void DidResolveURL(const storage::FileSystemInfo& info, const base::FilePath& file_path, bool is_directory) { resolve_callback_.Run(info, file_path, is_directory); } void DidWrite(int64 bytes, bool complete) { write_callback_.Run(bytes, complete); } private: CallbackDispatcher() {} StatusCallback status_callback_; MetadataCallback metadata_callback_; CreateSnapshotFileCallback snapshot_callback_; ReadDirectoryCallback directory_callback_; OpenFileSystemCallback filesystem_callback_; ResolveURLCallback resolve_callback_; WriteCallback write_callback_; StatusCallback error_callback_; DISALLOW_COPY_AND_ASSIGN(CallbackDispatcher); }; FileSystemDispatcher::FileSystemDispatcher() { } FileSystemDispatcher::~FileSystemDispatcher() { // Make sure we fire all the remaining callbacks. for (IDMap::iterator iter(&dispatchers_); !iter.IsAtEnd(); iter.Advance()) { int request_id = iter.GetCurrentKey(); CallbackDispatcher* dispatcher = iter.GetCurrentValue(); DCHECK(dispatcher); dispatcher->DidFail(base::File::FILE_ERROR_ABORT); dispatchers_.Remove(request_id); } } bool FileSystemDispatcher::OnMessageReceived(const IPC::Message& msg) { bool handled = true; IPC_BEGIN_MESSAGE_MAP(FileSystemDispatcher, msg) IPC_MESSAGE_HANDLER(FileSystemMsg_DidOpenFileSystem, OnDidOpenFileSystem) IPC_MESSAGE_HANDLER(FileSystemMsg_DidResolveURL, OnDidResolveURL) IPC_MESSAGE_HANDLER(FileSystemMsg_DidSucceed, OnDidSucceed) IPC_MESSAGE_HANDLER(FileSystemMsg_DidReadDirectory, OnDidReadDirectory) IPC_MESSAGE_HANDLER(FileSystemMsg_DidReadMetadata, OnDidReadMetadata) IPC_MESSAGE_HANDLER(FileSystemMsg_DidCreateSnapshotFile, OnDidCreateSnapshotFile) IPC_MESSAGE_HANDLER(FileSystemMsg_DidFail, OnDidFail) IPC_MESSAGE_HANDLER(FileSystemMsg_DidWrite, OnDidWrite) IPC_MESSAGE_UNHANDLED(handled = false) IPC_END_MESSAGE_MAP() return handled; } void FileSystemDispatcher::OpenFileSystem( const GURL& origin_url, storage::FileSystemType type, const OpenFileSystemCallback& success_callback, const StatusCallback& error_callback) { int request_id = dispatchers_.Add( CallbackDispatcher::Create(success_callback, error_callback)); ChildThreadImpl::current()->Send(new FileSystemHostMsg_OpenFileSystem( request_id, origin_url, type)); } void FileSystemDispatcher::ResolveURL( const GURL& filesystem_url, const ResolveURLCallback& success_callback, const StatusCallback& error_callback) { int request_id = dispatchers_.Add( CallbackDispatcher::Create(success_callback, error_callback)); ChildThreadImpl::current()->Send(new FileSystemHostMsg_ResolveURL( request_id, filesystem_url)); } void FileSystemDispatcher::DeleteFileSystem(const GURL& origin_url, storage::FileSystemType type, const StatusCallback& callback) { int request_id = dispatchers_.Add(CallbackDispatcher::Create(callback)); ChildThreadImpl::current()->Send(new FileSystemHostMsg_DeleteFileSystem( request_id, origin_url, type)); } void FileSystemDispatcher::Move( const GURL& src_path, const GURL& dest_path, const StatusCallback& callback) { int request_id = dispatchers_.Add(CallbackDispatcher::Create(callback)); ChildThreadImpl::current()->Send(new FileSystemHostMsg_Move( request_id, src_path, dest_path)); } void FileSystemDispatcher::Copy( const GURL& src_path, const GURL& dest_path, const StatusCallback& callback) { int request_id = dispatchers_.Add(CallbackDispatcher::Create(callback)); ChildThreadImpl::current()->Send(new FileSystemHostMsg_Copy( request_id, src_path, dest_path)); } void FileSystemDispatcher::Remove( const GURL& path, bool recursive, const StatusCallback& callback) { int request_id = dispatchers_.Add(CallbackDispatcher::Create(callback)); ChildThreadImpl::current()->Send( new FileSystemHostMsg_Remove(request_id, path, recursive)); } void FileSystemDispatcher::ReadMetadata( const GURL& path, const MetadataCallback& success_callback, const StatusCallback& error_callback) { int request_id = dispatchers_.Add( CallbackDispatcher::Create(success_callback, error_callback)); ChildThreadImpl::current()->Send( new FileSystemHostMsg_ReadMetadata(request_id, path)); } void FileSystemDispatcher::CreateFile( const GURL& path, bool exclusive, const StatusCallback& callback) { int request_id = dispatchers_.Add(CallbackDispatcher::Create(callback)); ChildThreadImpl::current()->Send(new FileSystemHostMsg_Create( request_id, path, exclusive, false /* is_directory */, false /* recursive */)); } void FileSystemDispatcher::CreateDirectory( const GURL& path, bool exclusive, bool recursive, const StatusCallback& callback) { int request_id = dispatchers_.Add(CallbackDispatcher::Create(callback)); ChildThreadImpl::current()->Send(new FileSystemHostMsg_Create( request_id, path, exclusive, true /* is_directory */, recursive)); } void FileSystemDispatcher::Exists( const GURL& path, bool is_directory, const StatusCallback& callback) { int request_id = dispatchers_.Add(CallbackDispatcher::Create(callback)); ChildThreadImpl::current()->Send( new FileSystemHostMsg_Exists(request_id, path, is_directory)); } void FileSystemDispatcher::ReadDirectory( const GURL& path, const ReadDirectoryCallback& success_callback, const StatusCallback& error_callback) { int request_id = dispatchers_.Add( CallbackDispatcher::Create(success_callback, error_callback)); ChildThreadImpl::current()->Send( new FileSystemHostMsg_ReadDirectory(request_id, path)); } void FileSystemDispatcher::Truncate( const GURL& path, int64 offset, int* request_id_out, const StatusCallback& callback) { int request_id = dispatchers_.Add(CallbackDispatcher::Create(callback)); ChildThreadImpl::current()->Send( new FileSystemHostMsg_Truncate(request_id, path, offset)); if (request_id_out) *request_id_out = request_id; } void FileSystemDispatcher::Write( const GURL& path, const std::string& blob_id, int64 offset, int* request_id_out, const WriteCallback& success_callback, const StatusCallback& error_callback) { int request_id = dispatchers_.Add( CallbackDispatcher::Create(success_callback, error_callback)); ChildThreadImpl::current()->Send( new FileSystemHostMsg_Write(request_id, path, blob_id, offset)); if (request_id_out) *request_id_out = request_id; } void FileSystemDispatcher::Cancel( int request_id_to_cancel, const StatusCallback& callback) { int request_id = dispatchers_.Add(CallbackDispatcher::Create(callback)); ChildThreadImpl::current()->Send(new FileSystemHostMsg_CancelWrite( request_id, request_id_to_cancel)); } void FileSystemDispatcher::TouchFile( const GURL& path, const base::Time& last_access_time, const base::Time& last_modified_time, const StatusCallback& callback) { int request_id = dispatchers_.Add(CallbackDispatcher::Create(callback)); ChildThreadImpl::current()->Send( new FileSystemHostMsg_TouchFile( request_id, path, last_access_time, last_modified_time)); } void FileSystemDispatcher::CreateSnapshotFile( const GURL& file_path, const CreateSnapshotFileCallback& success_callback, const StatusCallback& error_callback) { int request_id = dispatchers_.Add( CallbackDispatcher::Create(success_callback, error_callback)); ChildThreadImpl::current()->Send( new FileSystemHostMsg_CreateSnapshotFile( request_id, file_path)); } void FileSystemDispatcher::OnDidOpenFileSystem(int request_id, const std::string& name, const GURL& root) { DCHECK(root.is_valid()); CallbackDispatcher* dispatcher = dispatchers_.Lookup(request_id); DCHECK(dispatcher); dispatcher->DidOpenFileSystem(name, root); dispatchers_.Remove(request_id); } void FileSystemDispatcher::OnDidResolveURL(int request_id, const storage::FileSystemInfo& info, const base::FilePath& file_path, bool is_directory) { DCHECK(info.root_url.is_valid()); CallbackDispatcher* dispatcher = dispatchers_.Lookup(request_id); DCHECK(dispatcher); dispatcher->DidResolveURL(info, file_path, is_directory); dispatchers_.Remove(request_id); } void FileSystemDispatcher::OnDidSucceed(int request_id) { CallbackDispatcher* dispatcher = dispatchers_.Lookup(request_id); DCHECK(dispatcher); dispatcher->DidSucceed(); dispatchers_.Remove(request_id); } void FileSystemDispatcher::OnDidReadMetadata( int request_id, const base::File::Info& file_info) { CallbackDispatcher* dispatcher = dispatchers_.Lookup(request_id); DCHECK(dispatcher); dispatcher->DidReadMetadata(file_info); dispatchers_.Remove(request_id); } void FileSystemDispatcher::OnDidCreateSnapshotFile( int request_id, const base::File::Info& file_info, const base::FilePath& platform_path) { CallbackDispatcher* dispatcher = dispatchers_.Lookup(request_id); DCHECK(dispatcher); dispatcher->DidCreateSnapshotFile(file_info, platform_path, request_id); dispatchers_.Remove(request_id); } void FileSystemDispatcher::OnDidReadDirectory( int request_id, const std::vector& entries, bool has_more) { CallbackDispatcher* dispatcher = dispatchers_.Lookup(request_id); DCHECK(dispatcher); dispatcher->DidReadDirectory(entries, has_more); if (!has_more) dispatchers_.Remove(request_id); } void FileSystemDispatcher::OnDidFail( int request_id, base::File::Error error_code) { CallbackDispatcher* dispatcher = dispatchers_.Lookup(request_id); DCHECK(dispatcher); dispatcher->DidFail(error_code); dispatchers_.Remove(request_id); } void FileSystemDispatcher::OnDidWrite( int request_id, int64 bytes, bool complete) { CallbackDispatcher* dispatcher = dispatchers_.Lookup(request_id); DCHECK(dispatcher); dispatcher->DidWrite(bytes, complete); if (complete) dispatchers_.Remove(request_id); } } // namespace content