blob: 27737286999e0f9eaaf27510806567f38c44b08c [file] [log] [blame]
// Copyright 2013 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/webfilesystem_impl.h"
#include <stddef.h>
#include <tuple>
#include "base/bind.h"
#include "base/lazy_instance.h"
#include "base/logging.h"
#include "base/macros.h"
#include "base/strings/utf_string_conversions.h"
#include "base/synchronization/waitable_event.h"
#include "base/threading/thread_local.h"
#include "base/threading/thread_task_runner_handle.h"
#include "content/child/child_thread_impl.h"
#include "content/child/file_info_util.h"
#include "content/child/fileapi/file_system_dispatcher.h"
#include "content/child/fileapi/webfilewriter_impl.h"
#include "content/common/fileapi/file_system_messages.h"
#include "storage/common/fileapi/directory_entry.h"
#include "storage/common/fileapi/file_system_util.h"
#include "third_party/WebKit/public/platform/FilePathConversion.h"
#include "third_party/WebKit/public/platform/WebFileInfo.h"
#include "third_party/WebKit/public/platform/WebFileSystemCallbacks.h"
#include "third_party/WebKit/public/platform/WebString.h"
#include "third_party/WebKit/public/platform/WebURL.h"
#include "url/gurl.h"
using blink::WebFileInfo;
using blink::WebFileSystemCallbacks;
using blink::WebFileSystemEntry;
using blink::WebString;
using blink::WebURL;
using blink::WebVector;
namespace content {
class WebFileSystemImpl::WaitableCallbackResults
: public base::RefCountedThreadSafe<WaitableCallbackResults> {
public:
WaitableCallbackResults()
: results_available_event_(
base::WaitableEvent::ResetPolicy::MANUAL,
base::WaitableEvent::InitialState::NOT_SIGNALED) {}
void AddResultsAndSignal(const base::Closure& results_closure) {
base::AutoLock lock(lock_);
results_closures_.push_back(results_closure);
results_available_event_.Signal();
}
void WaitAndRun() {
results_available_event_.Wait();
Run();
}
void Run() {
std::vector<base::Closure> closures;
{
base::AutoLock lock(lock_);
results_closures_.swap(closures);
results_available_event_.Reset();
}
for (size_t i = 0; i < closures.size(); ++i)
closures[i].Run();
}
private:
friend class base::RefCountedThreadSafe<WaitableCallbackResults>;
~WaitableCallbackResults() {}
base::Lock lock_;
base::WaitableEvent results_available_event_;
std::vector<base::Closure> results_closures_;
DISALLOW_COPY_AND_ASSIGN(WaitableCallbackResults);
};
namespace {
typedef WebFileSystemImpl::WaitableCallbackResults WaitableCallbackResults;
base::LazyInstance<base::ThreadLocalPointer<WebFileSystemImpl> >::Leaky
g_webfilesystem_tls = LAZY_INSTANCE_INITIALIZER;
void DidReceiveSnapshotFile(int request_id) {
if (ChildThreadImpl::current())
ChildThreadImpl::current()->Send(
new FileSystemHostMsg_DidReceiveSnapshotFile(request_id));
}
template <typename Method, typename Params>
void CallDispatcherOnMainThread(
const scoped_refptr<base::SingleThreadTaskRunner>& main_thread_task_runner,
Method method, const Params& params,
WaitableCallbackResults* waitable_results) {
if (!main_thread_task_runner->RunsTasksOnCurrentThread()) {
main_thread_task_runner->PostTask(
FROM_HERE,
base::Bind(&CallDispatcherOnMainThread<Method, Params>,
main_thread_task_runner, method, params, nullptr));
if (!waitable_results)
return;
waitable_results->WaitAndRun();
}
if (!ChildThreadImpl::current() ||
!ChildThreadImpl::current()->file_system_dispatcher())
return;
DCHECK(!waitable_results);
DispatchToMethod(ChildThreadImpl::current()->file_system_dispatcher(),
method, params);
}
enum CallbacksUnregisterMode {
UNREGISTER_CALLBACKS,
DO_NOT_UNREGISTER_CALLBACKS,
};
// Bridging functions that convert the arguments into Blink objects
// (e.g. WebFileInfo, WebString, WebVector<WebFileSystemEntry>)
// and call WebFileSystemCallbacks's methods.
// These are called by RunCallbacks after crossing threads to ensure
// thread safety, because the Blink objects cannot be passed across
// threads by base::Bind().
void DidSucceed(WebFileSystemCallbacks* callbacks) {
callbacks->didSucceed();
}
void DidReadMetadata(const base::File::Info& file_info,
WebFileSystemCallbacks* callbacks) {
WebFileInfo web_file_info;
FileInfoToWebFileInfo(file_info, &web_file_info);
callbacks->didReadMetadata(web_file_info);
}
void DidReadDirectory(const std::vector<storage::DirectoryEntry>& entries,
bool has_more,
WebFileSystemCallbacks* callbacks) {
WebVector<WebFileSystemEntry> file_system_entries(entries.size());
for (size_t i = 0; i < entries.size(); ++i) {
file_system_entries[i].name =
blink::FilePathToWebString(base::FilePath(entries[i].name));
file_system_entries[i].isDirectory = entries[i].is_directory;
}
callbacks->didReadDirectory(file_system_entries, has_more);
}
void DidOpenFileSystem(const std::string& name,
const GURL& root,
WebFileSystemCallbacks* callbacks) {
callbacks->didOpenFileSystem(blink::WebString::fromUTF8(name), root);
}
void DidResolveURL(const std::string& name,
const GURL& root_url,
storage::FileSystemType mount_type,
const base::FilePath& file_path,
bool is_directory,
WebFileSystemCallbacks* callbacks) {
callbacks->didResolveURL(blink::WebString::fromUTF8(name), root_url,
static_cast<blink::WebFileSystemType>(mount_type),
blink::FilePathToWebString(file_path), is_directory);
}
void DidFail(base::File::Error error, WebFileSystemCallbacks* callbacks) {
callbacks->didFail(storage::FileErrorToWebFileError(error));
}
// Run WebFileSystemCallbacks's |method| with |params|.
void RunCallbacks(
int callbacks_id,
const base::Callback<void(WebFileSystemCallbacks*)>& callback,
CallbacksUnregisterMode callbacks_unregister_mode) {
WebFileSystemImpl* filesystem =
WebFileSystemImpl::ThreadSpecificInstance(NULL);
if (!filesystem)
return;
WebFileSystemCallbacks callbacks = filesystem->GetCallbacks(callbacks_id);
if (callbacks_unregister_mode == UNREGISTER_CALLBACKS)
filesystem->UnregisterCallbacks(callbacks_id);
callback.Run(&callbacks);
}
void DispatchResultsClosure(
const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
int callbacks_id,
WaitableCallbackResults* waitable_results,
const base::Closure& results_closure) {
if (task_runner->BelongsToCurrentThread()) {
results_closure.Run();
return;
}
if (waitable_results) {
// If someone is waiting, this should result in running the closure.
waitable_results->AddResultsAndSignal(results_closure);
// In case no one is waiting, post a task to run the closure.
task_runner->PostTask(FROM_HERE,
base::Bind(&WaitableCallbackResults::Run,
make_scoped_refptr(waitable_results)));
return;
}
task_runner->PostTask(FROM_HERE, results_closure);
}
void CallbackFileSystemCallbacks(
const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
int callbacks_id,
WaitableCallbackResults* waitable_results,
const base::Callback<void(WebFileSystemCallbacks*)>& callback,
CallbacksUnregisterMode callbacksunregister_mode) {
DispatchResultsClosure(task_runner, callbacks_id, waitable_results,
base::Bind(&RunCallbacks, callbacks_id, callback,
callbacksunregister_mode));
}
//-----------------------------------------------------------------------------
// Callback adapters. Callbacks must be called on the original calling thread,
// so these callback adapters relay back the results to the calling thread
// if necessary.
void OpenFileSystemCallbackAdapter(
const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
int callbacks_id,
WaitableCallbackResults* waitable_results,
const std::string& name,
const GURL& root) {
CallbackFileSystemCallbacks(task_runner, callbacks_id, waitable_results,
base::Bind(&DidOpenFileSystem, name, root),
UNREGISTER_CALLBACKS);
}
void ResolveURLCallbackAdapter(
const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
int callbacks_id,
WaitableCallbackResults* waitable_results,
const storage::FileSystemInfo& info,
const base::FilePath& file_path,
bool is_directory) {
base::FilePath normalized_path(
storage::VirtualPath::GetNormalizedFilePath(file_path));
CallbackFileSystemCallbacks(
task_runner, callbacks_id, waitable_results,
base::Bind(&DidResolveURL, info.name, info.root_url, info.mount_type,
normalized_path, is_directory),
UNREGISTER_CALLBACKS);
}
void StatusCallbackAdapter(
const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
int callbacks_id,
WaitableCallbackResults* waitable_results,
base::File::Error error) {
if (error == base::File::FILE_OK) {
CallbackFileSystemCallbacks(task_runner, callbacks_id, waitable_results,
base::Bind(&DidSucceed), UNREGISTER_CALLBACKS);
} else {
CallbackFileSystemCallbacks(task_runner, callbacks_id, waitable_results,
base::Bind(&DidFail, error),
UNREGISTER_CALLBACKS);
}
}
void ReadMetadataCallbackAdapter(
const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
int callbacks_id,
WaitableCallbackResults* waitable_results,
const base::File::Info& file_info) {
CallbackFileSystemCallbacks(task_runner, callbacks_id, waitable_results,
base::Bind(&DidReadMetadata, file_info),
UNREGISTER_CALLBACKS);
}
void ReadDirectoryCallbackAdapter(
const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
int callbacks_id,
WaitableCallbackResults* waitable_results,
const std::vector<storage::DirectoryEntry>& entries,
bool has_more) {
CallbackFileSystemCallbacks(
task_runner, callbacks_id, waitable_results,
base::Bind(&DidReadDirectory, entries, has_more),
has_more ? DO_NOT_UNREGISTER_CALLBACKS : UNREGISTER_CALLBACKS);
}
void DidCreateFileWriter(
int callbacks_id,
const GURL& path,
blink::WebFileWriterClient* client,
const scoped_refptr<base::SingleThreadTaskRunner>& main_thread_task_runner,
const base::File::Info& file_info) {
WebFileSystemImpl* filesystem =
WebFileSystemImpl::ThreadSpecificInstance(NULL);
if (!filesystem)
return;
WebFileSystemCallbacks callbacks = filesystem->GetCallbacks(callbacks_id);
filesystem->UnregisterCallbacks(callbacks_id);
if (file_info.is_directory || file_info.size < 0) {
callbacks.didFail(blink::WebFileErrorInvalidState);
return;
}
WebFileWriterImpl::Type type =
callbacks.shouldBlockUntilCompletion() ?
WebFileWriterImpl::TYPE_SYNC : WebFileWriterImpl::TYPE_ASYNC;
callbacks.didCreateFileWriter(
new WebFileWriterImpl(path, client, type, main_thread_task_runner),
file_info.size);
}
void CreateFileWriterCallbackAdapter(
const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
int callbacks_id,
WaitableCallbackResults* waitable_results,
const scoped_refptr<base::SingleThreadTaskRunner>& main_thread_task_runner,
const GURL& path,
blink::WebFileWriterClient* client,
const base::File::Info& file_info) {
DispatchResultsClosure(
task_runner, callbacks_id, waitable_results,
base::Bind(&DidCreateFileWriter, callbacks_id, path, client,
main_thread_task_runner, file_info));
}
void DidCreateSnapshotFile(
int callbacks_id,
const scoped_refptr<base::SingleThreadTaskRunner>& main_thread_task_runner,
const base::File::Info& file_info,
const base::FilePath& platform_path,
int request_id) {
WebFileSystemImpl* filesystem =
WebFileSystemImpl::ThreadSpecificInstance(NULL);
if (!filesystem)
return;
WebFileSystemCallbacks callbacks = filesystem->GetCallbacks(callbacks_id);
filesystem->UnregisterCallbacks(callbacks_id);
WebFileInfo web_file_info;
FileInfoToWebFileInfo(file_info, &web_file_info);
web_file_info.platformPath = blink::FilePathToWebString(platform_path);
callbacks.didCreateSnapshotFile(web_file_info);
// TODO(michaeln,kinuko): Use ThreadSafeSender when Blob becomes
// non-bridge model.
main_thread_task_runner->PostTask(
FROM_HERE, base::Bind(&DidReceiveSnapshotFile, request_id));
}
void CreateSnapshotFileCallbackAdapter(
const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
int callbacks_id,
WaitableCallbackResults* waitable_results,
const scoped_refptr<base::SingleThreadTaskRunner>& main_thread_task_runner,
const base::File::Info& file_info,
const base::FilePath& platform_path,
int request_id) {
DispatchResultsClosure(
task_runner, callbacks_id, waitable_results,
base::Bind(&DidCreateSnapshotFile, callbacks_id, main_thread_task_runner,
file_info, platform_path, request_id));
}
} // namespace
//-----------------------------------------------------------------------------
// WebFileSystemImpl
WebFileSystemImpl* WebFileSystemImpl::ThreadSpecificInstance(
const scoped_refptr<base::SingleThreadTaskRunner>&
main_thread_task_runner) {
if (g_webfilesystem_tls.Pointer()->Get() || !main_thread_task_runner.get())
return g_webfilesystem_tls.Pointer()->Get();
WebFileSystemImpl* filesystem =
new WebFileSystemImpl(main_thread_task_runner);
if (WorkerThread::GetCurrentId())
WorkerThread::AddObserver(filesystem);
return filesystem;
}
void WebFileSystemImpl::DeleteThreadSpecificInstance() {
DCHECK(!WorkerThread::GetCurrentId());
if (g_webfilesystem_tls.Pointer()->Get())
delete g_webfilesystem_tls.Pointer()->Get();
}
WebFileSystemImpl::WebFileSystemImpl(
const scoped_refptr<base::SingleThreadTaskRunner>& main_thread_task_runner)
: main_thread_task_runner_(main_thread_task_runner),
next_callbacks_id_(1) {
g_webfilesystem_tls.Pointer()->Set(this);
}
WebFileSystemImpl::~WebFileSystemImpl() {
g_webfilesystem_tls.Pointer()->Set(NULL);
}
void WebFileSystemImpl::WillStopCurrentWorkerThread() {
delete this;
}
void WebFileSystemImpl::openFileSystem(
const blink::WebURL& storage_partition,
blink::WebFileSystemType type,
WebFileSystemCallbacks callbacks) {
int callbacks_id = RegisterCallbacks(callbacks);
scoped_refptr<WaitableCallbackResults> waitable_results =
MaybeCreateWaitableResults(callbacks, callbacks_id);
CallDispatcherOnMainThread(
main_thread_task_runner_, &FileSystemDispatcher::OpenFileSystem,
std::make_tuple(
GURL(storage_partition), static_cast<storage::FileSystemType>(type),
base::Bind(&OpenFileSystemCallbackAdapter,
base::ThreadTaskRunnerHandle::Get(), callbacks_id,
base::RetainedRef(waitable_results)),
base::Bind(&StatusCallbackAdapter,
base::ThreadTaskRunnerHandle::Get(), callbacks_id,
base::RetainedRef(waitable_results))),
waitable_results.get());
}
void WebFileSystemImpl::resolveURL(
const blink::WebURL& filesystem_url,
WebFileSystemCallbacks callbacks) {
int callbacks_id = RegisterCallbacks(callbacks);
scoped_refptr<WaitableCallbackResults> waitable_results =
MaybeCreateWaitableResults(callbacks, callbacks_id);
CallDispatcherOnMainThread(
main_thread_task_runner_, &FileSystemDispatcher::ResolveURL,
std::make_tuple(
GURL(filesystem_url),
base::Bind(&ResolveURLCallbackAdapter,
base::ThreadTaskRunnerHandle::Get(), callbacks_id,
base::RetainedRef(waitable_results)),
base::Bind(&StatusCallbackAdapter,
base::ThreadTaskRunnerHandle::Get(), callbacks_id,
base::RetainedRef(waitable_results))),
waitable_results.get());
}
void WebFileSystemImpl::move(
const blink::WebURL& src_path,
const blink::WebURL& dest_path,
WebFileSystemCallbacks callbacks) {
int callbacks_id = RegisterCallbacks(callbacks);
scoped_refptr<WaitableCallbackResults> waitable_results =
MaybeCreateWaitableResults(callbacks, callbacks_id);
CallDispatcherOnMainThread(
main_thread_task_runner_, &FileSystemDispatcher::Move,
std::make_tuple(
GURL(src_path), GURL(dest_path),
base::Bind(&StatusCallbackAdapter,
base::ThreadTaskRunnerHandle::Get(), callbacks_id,
base::RetainedRef(waitable_results))),
waitable_results.get());
}
void WebFileSystemImpl::copy(
const blink::WebURL& src_path,
const blink::WebURL& dest_path,
WebFileSystemCallbacks callbacks) {
int callbacks_id = RegisterCallbacks(callbacks);
scoped_refptr<WaitableCallbackResults> waitable_results =
MaybeCreateWaitableResults(callbacks, callbacks_id);
CallDispatcherOnMainThread(
main_thread_task_runner_, &FileSystemDispatcher::Copy,
std::make_tuple(
GURL(src_path), GURL(dest_path),
base::Bind(&StatusCallbackAdapter,
base::ThreadTaskRunnerHandle::Get(), callbacks_id,
base::RetainedRef(waitable_results))),
waitable_results.get());
}
void WebFileSystemImpl::remove(
const blink::WebURL& path,
WebFileSystemCallbacks callbacks) {
int callbacks_id = RegisterCallbacks(callbacks);
scoped_refptr<WaitableCallbackResults> waitable_results =
MaybeCreateWaitableResults(callbacks, callbacks_id);
CallDispatcherOnMainThread(
main_thread_task_runner_, &FileSystemDispatcher::Remove,
std::make_tuple(
GURL(path), false /* recursive */,
base::Bind(&StatusCallbackAdapter,
base::ThreadTaskRunnerHandle::Get(), callbacks_id,
base::RetainedRef(waitable_results))),
waitable_results.get());
}
void WebFileSystemImpl::removeRecursively(
const blink::WebURL& path,
WebFileSystemCallbacks callbacks) {
int callbacks_id = RegisterCallbacks(callbacks);
scoped_refptr<WaitableCallbackResults> waitable_results =
MaybeCreateWaitableResults(callbacks, callbacks_id);
CallDispatcherOnMainThread(
main_thread_task_runner_, &FileSystemDispatcher::Remove,
std::make_tuple(
GURL(path), true /* recursive */,
base::Bind(&StatusCallbackAdapter,
base::ThreadTaskRunnerHandle::Get(), callbacks_id,
base::RetainedRef(waitable_results))),
waitable_results.get());
}
void WebFileSystemImpl::readMetadata(
const blink::WebURL& path,
WebFileSystemCallbacks callbacks) {
int callbacks_id = RegisterCallbacks(callbacks);
scoped_refptr<WaitableCallbackResults> waitable_results =
MaybeCreateWaitableResults(callbacks, callbacks_id);
CallDispatcherOnMainThread(
main_thread_task_runner_, &FileSystemDispatcher::ReadMetadata,
std::make_tuple(
GURL(path),
base::Bind(&ReadMetadataCallbackAdapter,
base::ThreadTaskRunnerHandle::Get(), callbacks_id,
base::RetainedRef(waitable_results)),
base::Bind(&StatusCallbackAdapter,
base::ThreadTaskRunnerHandle::Get(), callbacks_id,
base::RetainedRef(waitable_results))),
waitable_results.get());
}
void WebFileSystemImpl::createFile(
const blink::WebURL& path,
bool exclusive,
WebFileSystemCallbacks callbacks) {
int callbacks_id = RegisterCallbacks(callbacks);
scoped_refptr<WaitableCallbackResults> waitable_results =
MaybeCreateWaitableResults(callbacks, callbacks_id);
CallDispatcherOnMainThread(
main_thread_task_runner_, &FileSystemDispatcher::CreateFile,
std::make_tuple(
GURL(path), exclusive,
base::Bind(&StatusCallbackAdapter,
base::ThreadTaskRunnerHandle::Get(), callbacks_id,
base::RetainedRef(waitable_results))),
waitable_results.get());
}
void WebFileSystemImpl::createDirectory(
const blink::WebURL& path,
bool exclusive,
WebFileSystemCallbacks callbacks) {
int callbacks_id = RegisterCallbacks(callbacks);
scoped_refptr<WaitableCallbackResults> waitable_results =
MaybeCreateWaitableResults(callbacks, callbacks_id);
CallDispatcherOnMainThread(
main_thread_task_runner_, &FileSystemDispatcher::CreateDirectory,
std::make_tuple(
GURL(path), exclusive, false /* recursive */,
base::Bind(&StatusCallbackAdapter,
base::ThreadTaskRunnerHandle::Get(), callbacks_id,
base::RetainedRef(waitable_results))),
waitable_results.get());
}
void WebFileSystemImpl::fileExists(
const blink::WebURL& path,
WebFileSystemCallbacks callbacks) {
int callbacks_id = RegisterCallbacks(callbacks);
scoped_refptr<WaitableCallbackResults> waitable_results =
MaybeCreateWaitableResults(callbacks, callbacks_id);
CallDispatcherOnMainThread(
main_thread_task_runner_, &FileSystemDispatcher::Exists,
std::make_tuple(
GURL(path), false /* directory */,
base::Bind(&StatusCallbackAdapter,
base::ThreadTaskRunnerHandle::Get(), callbacks_id,
base::RetainedRef(waitable_results))),
waitable_results.get());
}
void WebFileSystemImpl::directoryExists(
const blink::WebURL& path,
WebFileSystemCallbacks callbacks) {
int callbacks_id = RegisterCallbacks(callbacks);
scoped_refptr<WaitableCallbackResults> waitable_results =
MaybeCreateWaitableResults(callbacks, callbacks_id);
CallDispatcherOnMainThread(
main_thread_task_runner_, &FileSystemDispatcher::Exists,
std::make_tuple(
GURL(path), true /* directory */,
base::Bind(&StatusCallbackAdapter,
base::ThreadTaskRunnerHandle::Get(), callbacks_id,
base::RetainedRef(waitable_results))),
waitable_results.get());
}
int WebFileSystemImpl::readDirectory(
const blink::WebURL& path,
WebFileSystemCallbacks callbacks) {
int callbacks_id = RegisterCallbacks(callbacks);
scoped_refptr<WaitableCallbackResults> waitable_results =
MaybeCreateWaitableResults(callbacks, callbacks_id);
CallDispatcherOnMainThread(
main_thread_task_runner_, &FileSystemDispatcher::ReadDirectory,
std::make_tuple(
GURL(path),
base::Bind(&ReadDirectoryCallbackAdapter,
base::ThreadTaskRunnerHandle::Get(), callbacks_id,
base::RetainedRef(waitable_results)),
base::Bind(&StatusCallbackAdapter,
base::ThreadTaskRunnerHandle::Get(), callbacks_id,
base::RetainedRef(waitable_results))),
waitable_results.get());
return callbacks_id;
}
void WebFileSystemImpl::createFileWriter(
const WebURL& path,
blink::WebFileWriterClient* client,
WebFileSystemCallbacks callbacks) {
int callbacks_id = RegisterCallbacks(callbacks);
scoped_refptr<WaitableCallbackResults> waitable_results =
MaybeCreateWaitableResults(callbacks, callbacks_id);
CallDispatcherOnMainThread(
main_thread_task_runner_, &FileSystemDispatcher::ReadMetadata,
std::make_tuple(
GURL(path),
base::Bind(&CreateFileWriterCallbackAdapter,
base::ThreadTaskRunnerHandle::Get(), callbacks_id,
base::RetainedRef(waitable_results),
main_thread_task_runner_, GURL(path), client),
base::Bind(&StatusCallbackAdapter,
base::ThreadTaskRunnerHandle::Get(), callbacks_id,
base::RetainedRef(waitable_results))),
waitable_results.get());
}
void WebFileSystemImpl::createSnapshotFileAndReadMetadata(
const blink::WebURL& path,
WebFileSystemCallbacks callbacks) {
int callbacks_id = RegisterCallbacks(callbacks);
scoped_refptr<WaitableCallbackResults> waitable_results =
MaybeCreateWaitableResults(callbacks, callbacks_id);
CallDispatcherOnMainThread(
main_thread_task_runner_, &FileSystemDispatcher::CreateSnapshotFile,
std::make_tuple(
GURL(path),
base::Bind(&CreateSnapshotFileCallbackAdapter,
base::ThreadTaskRunnerHandle::Get(), callbacks_id,
base::RetainedRef(waitable_results),
main_thread_task_runner_),
base::Bind(&StatusCallbackAdapter,
base::ThreadTaskRunnerHandle::Get(), callbacks_id,
base::RetainedRef(waitable_results))),
waitable_results.get());
}
bool WebFileSystemImpl::waitForAdditionalResult(int callbacksId) {
WaitableCallbackResultsMap::iterator found =
waitable_results_.find(callbacksId);
if (found == waitable_results_.end())
return false;
found->second->WaitAndRun();
return true;
}
int WebFileSystemImpl::RegisterCallbacks(
const WebFileSystemCallbacks& callbacks) {
DCHECK(CalledOnValidThread());
int id = next_callbacks_id_++;
callbacks_[id] = callbacks;
return id;
}
WebFileSystemCallbacks WebFileSystemImpl::GetCallbacks(int callbacks_id) {
DCHECK(CalledOnValidThread());
CallbacksMap::iterator found = callbacks_.find(callbacks_id);
DCHECK(found != callbacks_.end());
return found->second;
}
void WebFileSystemImpl::UnregisterCallbacks(int callbacks_id) {
DCHECK(CalledOnValidThread());
CallbacksMap::iterator found = callbacks_.find(callbacks_id);
DCHECK(found != callbacks_.end());
callbacks_.erase(found);
waitable_results_.erase(callbacks_id);
}
WaitableCallbackResults* WebFileSystemImpl::MaybeCreateWaitableResults(
const WebFileSystemCallbacks& callbacks, int callbacks_id) {
if (!callbacks.shouldBlockUntilCompletion())
return NULL;
WaitableCallbackResults* results = new WaitableCallbackResults();
waitable_results_[callbacks_id] = results;
return results;
}
} // namespace content