blob: 8d886dcc54bd1c4c0015a4bfa43eabec68612d25 [file] [log] [blame]
// Copyright (c) 2011 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/file_system/file_system_dispatcher_host.h"
#include <string>
#include <vector>
#include "base/file_path.h"
#include "base/platform_file.h"
#include "base/threading/thread.h"
#include "base/time.h"
#include "content/browser/resource_context.h"
#include "content/common/file_system_messages.h"
#include "googleurl/src/gurl.h"
#include "ipc/ipc_platform_file.h"
#include "net/url_request/url_request_context.h"
#include "webkit/fileapi/file_system_callback_dispatcher.h"
#include "webkit/fileapi/file_system_context.h"
#include "webkit/fileapi/file_system_operation.h"
#include "webkit/fileapi/file_system_operation.h"
#include "webkit/fileapi/file_system_path_manager.h"
#include "webkit/fileapi/file_system_quota_util.h"
#include "webkit/fileapi/file_system_util.h"
using fileapi::FileSystemCallbackDispatcher;
using fileapi::FileSystemFileUtil;
using fileapi::FileSystemOperation;
using fileapi::FileSystemOperationContext;
class BrowserFileSystemCallbackDispatcher
: public FileSystemCallbackDispatcher {
public:
BrowserFileSystemCallbackDispatcher(
FileSystemDispatcherHost* dispatcher_host, int request_id)
: dispatcher_host_(dispatcher_host),
request_id_(request_id) {
DCHECK(dispatcher_host_);
}
virtual ~BrowserFileSystemCallbackDispatcher() {
dispatcher_host_->UnregisterOperation(request_id_);
}
virtual void DidSucceed() {
dispatcher_host_->Send(new FileSystemMsg_DidSucceed(request_id_));
}
virtual void DidReadMetadata(
const base::PlatformFileInfo& info,
const FilePath& platform_path) {
dispatcher_host_->Send(new FileSystemMsg_DidReadMetadata(
request_id_, info, platform_path));
}
virtual void DidReadDirectory(
const std::vector<base::FileUtilProxy::Entry>& entries, bool has_more) {
dispatcher_host_->Send(new FileSystemMsg_DidReadDirectory(
request_id_, entries, has_more));
}
virtual void DidOpenFileSystem(const std::string& name,
const GURL& root) {
dispatcher_host_->Send(
new FileSystemMsg_OpenComplete(
request_id_, root.is_valid(), name, root));
}
virtual void DidFail(base::PlatformFileError error_code) {
dispatcher_host_->Send(new FileSystemMsg_DidFail(request_id_, error_code));
}
virtual void DidWrite(int64 bytes, bool complete) {
dispatcher_host_->Send(new FileSystemMsg_DidWrite(
request_id_, bytes, complete));
}
virtual void DidOpenFile(
base::PlatformFile file,
base::ProcessHandle peer_handle) {
IPC::PlatformFileForTransit file_for_transit =
file != base::kInvalidPlatformFileValue ?
IPC::GetFileHandleForProcess(file, peer_handle, true) :
IPC::InvalidPlatformFileForTransit();
dispatcher_host_->Send(new FileSystemMsg_DidOpenFile(
request_id_, file_for_transit));
}
private:
scoped_refptr<FileSystemDispatcherHost> dispatcher_host_;
int request_id_;
};
FileSystemDispatcherHost::FileSystemDispatcherHost(
const content::ResourceContext* resource_context)
: context_(NULL),
resource_context_(resource_context),
request_context_(NULL) {
DCHECK(resource_context_);
}
FileSystemDispatcherHost::FileSystemDispatcherHost(
net::URLRequestContext* request_context,
fileapi::FileSystemContext* file_system_context)
: context_(file_system_context),
resource_context_(NULL),
request_context_(request_context) {
DCHECK(request_context_);
DCHECK(context_);
}
FileSystemDispatcherHost::~FileSystemDispatcherHost() {
}
void FileSystemDispatcherHost::OnChannelConnected(int32 peer_pid) {
BrowserMessageFilter::OnChannelConnected(peer_pid);
if (resource_context_) {
DCHECK(!request_context_);
request_context_ = resource_context_->request_context();
DCHECK(!context_);
context_ = resource_context_->file_system_context();
resource_context_ = NULL;
}
DCHECK(request_context_);
DCHECK(context_);
}
void FileSystemDispatcherHost::OverrideThreadForMessage(
const IPC::Message& message,
BrowserThread::ID* thread) {
if (message.type() == FileSystemHostMsg_SyncGetPlatformPath::ID)
*thread = BrowserThread::FILE;
}
bool FileSystemDispatcherHost::OnMessageReceived(
const IPC::Message& message, bool* message_was_ok) {
*message_was_ok = true;
bool handled = true;
IPC_BEGIN_MESSAGE_MAP_EX(FileSystemDispatcherHost, message, *message_was_ok)
IPC_MESSAGE_HANDLER(FileSystemHostMsg_Open, OnOpen)
IPC_MESSAGE_HANDLER(FileSystemHostMsg_Move, OnMove)
IPC_MESSAGE_HANDLER(FileSystemHostMsg_Copy, OnCopy)
IPC_MESSAGE_HANDLER(FileSystemMsg_Remove, OnRemove)
IPC_MESSAGE_HANDLER(FileSystemHostMsg_ReadMetadata, OnReadMetadata)
IPC_MESSAGE_HANDLER(FileSystemHostMsg_Create, OnCreate)
IPC_MESSAGE_HANDLER(FileSystemHostMsg_Exists, OnExists)
IPC_MESSAGE_HANDLER(FileSystemHostMsg_ReadDirectory, OnReadDirectory)
IPC_MESSAGE_HANDLER(FileSystemHostMsg_Write, OnWrite)
IPC_MESSAGE_HANDLER(FileSystemHostMsg_Truncate, OnTruncate)
IPC_MESSAGE_HANDLER(FileSystemHostMsg_TouchFile, OnTouchFile)
IPC_MESSAGE_HANDLER(FileSystemHostMsg_CancelWrite, OnCancel)
IPC_MESSAGE_HANDLER(FileSystemHostMsg_OpenFile, OnOpenFile)
IPC_MESSAGE_HANDLER(FileSystemHostMsg_WillUpdate, OnWillUpdate)
IPC_MESSAGE_HANDLER(FileSystemHostMsg_DidUpdate, OnDidUpdate)
IPC_MESSAGE_HANDLER(FileSystemHostMsg_SyncGetPlatformPath,
OnSyncGetPlatformPath)
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP_EX()
return handled;
}
void FileSystemDispatcherHost::OnOpen(
int request_id, const GURL& origin_url, fileapi::FileSystemType type,
int64 requested_size, bool create) {
GetNewOperation(request_id)->OpenFileSystem(origin_url, type, create);
}
void FileSystemDispatcherHost::OnMove(
int request_id, const GURL& src_path, const GURL& dest_path) {
GetNewOperation(request_id)->Move(src_path, dest_path);
}
void FileSystemDispatcherHost::OnCopy(
int request_id, const GURL& src_path, const GURL& dest_path) {
GetNewOperation(request_id)->Copy(src_path, dest_path);
}
void FileSystemDispatcherHost::OnRemove(
int request_id, const GURL& path, bool recursive) {
GetNewOperation(request_id)->Remove(path, recursive);
}
void FileSystemDispatcherHost::OnReadMetadata(
int request_id, const GURL& path) {
GetNewOperation(request_id)->GetMetadata(path);
}
void FileSystemDispatcherHost::OnCreate(
int request_id, const GURL& path, bool exclusive,
bool is_directory, bool recursive) {
if (is_directory)
GetNewOperation(request_id)->CreateDirectory(path, exclusive, recursive);
else
GetNewOperation(request_id)->CreateFile(path, exclusive);
}
void FileSystemDispatcherHost::OnExists(
int request_id, const GURL& path, bool is_directory) {
if (is_directory)
GetNewOperation(request_id)->DirectoryExists(path);
else
GetNewOperation(request_id)->FileExists(path);
}
void FileSystemDispatcherHost::OnReadDirectory(
int request_id, const GURL& path) {
GetNewOperation(request_id)->ReadDirectory(path);
}
void FileSystemDispatcherHost::OnWrite(
int request_id,
const GURL& path,
const GURL& blob_url,
int64 offset) {
GetNewOperation(request_id)->Write(
request_context_, path, blob_url, offset);
}
void FileSystemDispatcherHost::OnTruncate(
int request_id,
const GURL& path,
int64 length) {
GetNewOperation(request_id)->Truncate(path, length);
}
void FileSystemDispatcherHost::OnTouchFile(
int request_id,
const GURL& path,
const base::Time& last_access_time,
const base::Time& last_modified_time) {
GetNewOperation(request_id)->TouchFile(
path, last_access_time, last_modified_time);
}
void FileSystemDispatcherHost::OnCancel(
int request_id,
int request_id_to_cancel) {
FileSystemOperation* write = operations_.Lookup(
request_id_to_cancel);
if (write) {
// The cancel will eventually send both the write failure and the cancel
// success.
write->Cancel(GetNewOperation(request_id));
} else {
// The write already finished; report that we failed to stop it.
Send(new FileSystemMsg_DidFail(
request_id, base::PLATFORM_FILE_ERROR_INVALID_OPERATION));
}
}
void FileSystemDispatcherHost::OnOpenFile(
int request_id, const GURL& path, int file_flags) {
GetNewOperation(request_id)->OpenFile(path, file_flags, peer_handle());
}
void FileSystemDispatcherHost::OnWillUpdate(const GURL& path) {
GURL origin_url;
fileapi::FileSystemType type;
if (!CrackFileSystemURL(path, &origin_url, &type, NULL))
return;
fileapi::FileSystemQuotaUtil* quota_util = context_->GetQuotaUtil(type);
if (!quota_util)
return;
quota_util->proxy()->StartUpdateOrigin(origin_url, type);
}
void FileSystemDispatcherHost::OnDidUpdate(const GURL& path, int64 delta) {
GURL origin_url;
fileapi::FileSystemType type;
if (!CrackFileSystemURL(path, &origin_url, &type, NULL))
return;
fileapi::FileSystemQuotaUtil* quota_util = context_->GetQuotaUtil(type);
if (!quota_util)
return;
quota_util->proxy()->UpdateOriginUsage(
context_->quota_manager_proxy(), origin_url, type, delta);
quota_util->proxy()->EndUpdateOrigin(origin_url, type);
}
void FileSystemDispatcherHost::OnSyncGetPlatformPath(
const GURL& path, FilePath* platform_path) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
DCHECK(platform_path);
*platform_path = FilePath();
base::PlatformFileInfo info;
GURL origin_url;
fileapi::FileSystemType type;
FilePath virtual_path;
if (!CrackFileSystemURL(path, &origin_url, &type, &virtual_path))
return;
FileSystemFileUtil* file_util =
context_->path_manager()->GetFileSystemFileUtil(type);
if (!file_util)
return;
FileSystemOperationContext operation_context(context_, file_util);
operation_context.set_src_origin_url(origin_url);
operation_context.set_src_type(type);
file_util->GetFileInfo(&operation_context, virtual_path,
&info, platform_path);
}
FileSystemOperation* FileSystemDispatcherHost::GetNewOperation(
int request_id) {
BrowserFileSystemCallbackDispatcher* dispatcher =
new BrowserFileSystemCallbackDispatcher(this, request_id);
FileSystemOperation* operation = new FileSystemOperation(
dispatcher,
BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE),
context_,
NULL);
operations_.AddWithID(operation, request_id);
return operation;
}
void FileSystemDispatcherHost::UnregisterOperation(int request_id) {
DCHECK(operations_.Lookup(request_id));
operations_.Remove(request_id);
}