| // 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/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<storage::DirectoryEntry>& 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<CallbackDispatcher, IDMapOwnPointer>::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<storage::DirectoryEntry>& 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 |