Home | History | Annotate | Download | only in fileapi
      1 // Copyright 2013 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "content/child/fileapi/webfilesystem_impl.h"
      6 
      7 #include "base/bind.h"
      8 #include "base/lazy_instance.h"
      9 #include "base/logging.h"
     10 #include "base/message_loop/message_loop_proxy.h"
     11 #include "base/strings/utf_string_conversions.h"
     12 #include "base/synchronization/waitable_event.h"
     13 #include "base/threading/thread_local.h"
     14 #include "content/child/blink_glue.h"
     15 #include "content/child/child_thread.h"
     16 #include "content/child/fileapi/file_system_dispatcher.h"
     17 #include "content/child/fileapi/webfilewriter_impl.h"
     18 #include "content/child/worker_task_runner.h"
     19 #include "content/common/fileapi/file_system_messages.h"
     20 #include "third_party/WebKit/public/platform/WebFileInfo.h"
     21 #include "third_party/WebKit/public/platform/WebFileSystemCallbacks.h"
     22 #include "third_party/WebKit/public/platform/WebString.h"
     23 #include "third_party/WebKit/public/platform/WebURL.h"
     24 #include "third_party/WebKit/public/web/WebHeap.h"
     25 #include "url/gurl.h"
     26 #include "webkit/common/fileapi/directory_entry.h"
     27 #include "webkit/common/fileapi/file_system_util.h"
     28 
     29 using blink::WebFileInfo;
     30 using blink::WebFileSystemCallbacks;
     31 using blink::WebFileSystemEntry;
     32 using blink::WebString;
     33 using blink::WebURL;
     34 using blink::WebVector;
     35 
     36 namespace content {
     37 
     38 class WebFileSystemImpl::WaitableCallbackResults
     39     : public base::RefCountedThreadSafe<WaitableCallbackResults> {
     40  public:
     41   WaitableCallbackResults()
     42       : results_available_event_(true /* manual_reset */,
     43                                  false /* initially_signaled */) {}
     44 
     45   void AddResultsAndSignal(const base::Closure& results_closure) {
     46     base::AutoLock lock(lock_);
     47     results_closures_.push_back(results_closure);
     48     results_available_event_.Signal();
     49   }
     50 
     51   void WaitAndRun() {
     52     {
     53       blink::WebHeap::SafePointScope safe_point;
     54       results_available_event_.Wait();
     55     }
     56     Run();
     57   }
     58 
     59   void Run() {
     60     std::vector<base::Closure> closures;
     61     {
     62       base::AutoLock lock(lock_);
     63       results_closures_.swap(closures);
     64       results_available_event_.Reset();
     65     }
     66     for (size_t i = 0; i < closures.size(); ++i)
     67       closures[i].Run();
     68   }
     69 
     70  private:
     71   friend class base::RefCountedThreadSafe<WaitableCallbackResults>;
     72 
     73   ~WaitableCallbackResults() {}
     74 
     75   base::Lock lock_;
     76   base::WaitableEvent results_available_event_;
     77   std::vector<base::Closure> results_closures_;
     78   DISALLOW_COPY_AND_ASSIGN(WaitableCallbackResults);
     79 };
     80 
     81 namespace {
     82 
     83 typedef WebFileSystemImpl::WaitableCallbackResults WaitableCallbackResults;
     84 
     85 base::LazyInstance<base::ThreadLocalPointer<WebFileSystemImpl> >::Leaky
     86     g_webfilesystem_tls = LAZY_INSTANCE_INITIALIZER;
     87 
     88 void DidReceiveSnapshotFile(int request_id) {
     89   if (ChildThread::current())
     90     ChildThread::current()->Send(
     91         new FileSystemHostMsg_DidReceiveSnapshotFile(request_id));
     92 }
     93 
     94 int CurrentWorkerId() {
     95   return WorkerTaskRunner::Instance()->CurrentWorkerId();
     96 }
     97 
     98 template <typename Method, typename Params>
     99 void CallDispatcherOnMainThread(
    100     base::MessageLoopProxy* loop,
    101     Method method, const Params& params,
    102     WaitableCallbackResults* waitable_results) {
    103   if (!loop->RunsTasksOnCurrentThread()) {
    104     loop->PostTask(FROM_HERE,
    105                    base::Bind(&CallDispatcherOnMainThread<Method, Params>,
    106                               make_scoped_refptr(loop), method, params,
    107                               scoped_refptr<WaitableCallbackResults>()));
    108     if (!waitable_results)
    109       return;
    110     waitable_results->WaitAndRun();
    111   }
    112   if (!ChildThread::current() ||
    113       !ChildThread::current()->file_system_dispatcher())
    114     return;
    115 
    116   DCHECK(!waitable_results);
    117   DispatchToMethod(ChildThread::current()->file_system_dispatcher(),
    118                    method, params);
    119 }
    120 
    121 enum CallbacksUnregisterMode {
    122   UNREGISTER_CALLBACKS,
    123   DO_NOT_UNREGISTER_CALLBACKS,
    124 };
    125 
    126 // Run WebFileSystemCallbacks's |method| with |params|.
    127 template <typename Method, typename Params>
    128 void RunCallbacks(int callbacks_id, Method method, const Params& params,
    129                   CallbacksUnregisterMode callbacks_unregister_mode) {
    130   WebFileSystemImpl* filesystem =
    131       WebFileSystemImpl::ThreadSpecificInstance(NULL);
    132   if (!filesystem)
    133     return;
    134   WebFileSystemCallbacks callbacks = filesystem->GetCallbacks(callbacks_id);
    135   if (callbacks_unregister_mode == UNREGISTER_CALLBACKS)
    136     filesystem->UnregisterCallbacks(callbacks_id);
    137   DispatchToMethod(&callbacks, method, params);
    138 }
    139 
    140 void DispatchResultsClosure(int thread_id, int callbacks_id,
    141                             WaitableCallbackResults* waitable_results,
    142                             const base::Closure& results_closure) {
    143   if (thread_id != CurrentWorkerId()) {
    144     if (waitable_results) {
    145       // If someone is waiting, this should result in running the closure.
    146       waitable_results->AddResultsAndSignal(results_closure);
    147       // In case no one is waiting, post a task to run the closure.
    148       WorkerTaskRunner::Instance()->PostTask(
    149           thread_id,
    150           base::Bind(&WaitableCallbackResults::Run,
    151                      make_scoped_refptr(waitable_results)));
    152       return;
    153     }
    154     WorkerTaskRunner::Instance()->PostTask(thread_id, results_closure);
    155     return;
    156   }
    157   results_closure.Run();
    158 }
    159 
    160 template <typename Method, typename Params>
    161 void CallbackFileSystemCallbacks(
    162     int thread_id, int callbacks_id,
    163     WaitableCallbackResults* waitable_results,
    164     Method method, const Params& params,
    165     CallbacksUnregisterMode callbacks_unregister_mode) {
    166   DispatchResultsClosure(
    167       thread_id, callbacks_id, waitable_results,
    168       base::Bind(&RunCallbacks<Method, Params>, callbacks_id, method, params,
    169                  callbacks_unregister_mode));
    170 }
    171 
    172 //-----------------------------------------------------------------------------
    173 // Callback adapters. Callbacks must be called on the original calling thread,
    174 // so these callback adapters relay back the results to the calling thread
    175 // if necessary.
    176 
    177 void OpenFileSystemCallbackAdapter(
    178     int thread_id, int callbacks_id,
    179     WaitableCallbackResults* waitable_results,
    180     const std::string& name, const GURL& root) {
    181   CallbackFileSystemCallbacks(
    182       thread_id, callbacks_id, waitable_results,
    183       &WebFileSystemCallbacks::didOpenFileSystem,
    184       MakeTuple(base::UTF8ToUTF16(name), root),
    185       UNREGISTER_CALLBACKS);
    186 }
    187 
    188 void ResolveURLCallbackAdapter(
    189     int thread_id, int callbacks_id,
    190     WaitableCallbackResults* waitable_results,
    191     const fileapi::FileSystemInfo& info,
    192     const base::FilePath& file_path, bool is_directory) {
    193   base::FilePath normalized_path(
    194       fileapi::VirtualPath::GetNormalizedFilePath(file_path));
    195   CallbackFileSystemCallbacks(
    196       thread_id, callbacks_id, waitable_results,
    197       &WebFileSystemCallbacks::didResolveURL,
    198       MakeTuple(base::UTF8ToUTF16(info.name), info.root_url,
    199                 static_cast<blink::WebFileSystemType>(info.mount_type),
    200                 normalized_path.AsUTF16Unsafe(), is_directory),
    201       UNREGISTER_CALLBACKS);
    202 }
    203 
    204 void StatusCallbackAdapter(int thread_id, int callbacks_id,
    205                            WaitableCallbackResults* waitable_results,
    206                            base::File::Error error) {
    207   if (error == base::File::FILE_OK) {
    208     CallbackFileSystemCallbacks(
    209         thread_id, callbacks_id, waitable_results,
    210         &WebFileSystemCallbacks::didSucceed, MakeTuple(),
    211         UNREGISTER_CALLBACKS);
    212   } else {
    213     CallbackFileSystemCallbacks(
    214         thread_id, callbacks_id, waitable_results,
    215         &WebFileSystemCallbacks::didFail,
    216         MakeTuple(fileapi::FileErrorToWebFileError(error)),
    217         UNREGISTER_CALLBACKS);
    218   }
    219 }
    220 
    221 void ReadMetadataCallbackAdapter(int thread_id, int callbacks_id,
    222                                  WaitableCallbackResults* waitable_results,
    223                                  const base::File::Info& file_info) {
    224   WebFileInfo web_file_info;
    225   FileInfoToWebFileInfo(file_info, &web_file_info);
    226   CallbackFileSystemCallbacks(
    227       thread_id, callbacks_id, waitable_results,
    228       &WebFileSystemCallbacks::didReadMetadata,
    229       MakeTuple(web_file_info),
    230       UNREGISTER_CALLBACKS);
    231 }
    232 
    233 void ReadDirectoryCallbackAdapter(
    234     int thread_id, int callbacks_id, WaitableCallbackResults* waitable_results,
    235     const std::vector<fileapi::DirectoryEntry>& entries,
    236     bool has_more) {
    237   WebVector<WebFileSystemEntry> file_system_entries(entries.size());
    238   for (size_t i = 0; i < entries.size(); i++) {
    239     file_system_entries[i].name =
    240         base::FilePath(entries[i].name).AsUTF16Unsafe();
    241     file_system_entries[i].isDirectory = entries[i].is_directory;
    242   }
    243   CallbackFileSystemCallbacks(
    244       thread_id, callbacks_id, waitable_results,
    245       &WebFileSystemCallbacks::didReadDirectory,
    246       MakeTuple(file_system_entries, has_more),
    247       has_more ? DO_NOT_UNREGISTER_CALLBACKS : UNREGISTER_CALLBACKS);
    248 }
    249 
    250 void DidCreateFileWriter(
    251     int callbacks_id,
    252     const GURL& path,
    253     blink::WebFileWriterClient* client,
    254     base::MessageLoopProxy* main_thread_loop,
    255     const base::File::Info& file_info) {
    256   WebFileSystemImpl* filesystem =
    257       WebFileSystemImpl::ThreadSpecificInstance(NULL);
    258   if (!filesystem)
    259     return;
    260 
    261   WebFileSystemCallbacks callbacks = filesystem->GetCallbacks(callbacks_id);
    262   filesystem->UnregisterCallbacks(callbacks_id);
    263 
    264   if (file_info.is_directory || file_info.size < 0) {
    265     callbacks.didFail(blink::WebFileErrorInvalidState);
    266     return;
    267   }
    268   WebFileWriterImpl::Type type =
    269       callbacks.shouldBlockUntilCompletion() ?
    270           WebFileWriterImpl::TYPE_SYNC : WebFileWriterImpl::TYPE_ASYNC;
    271   callbacks.didCreateFileWriter(
    272       new WebFileWriterImpl(path, client, type, main_thread_loop),
    273       file_info.size);
    274 }
    275 
    276 void CreateFileWriterCallbackAdapter(
    277     int thread_id, int callbacks_id,
    278     WaitableCallbackResults* waitable_results,
    279     base::MessageLoopProxy* main_thread_loop,
    280     const GURL& path,
    281     blink::WebFileWriterClient* client,
    282     const base::File::Info& file_info) {
    283   DispatchResultsClosure(
    284       thread_id, callbacks_id, waitable_results,
    285       base::Bind(&DidCreateFileWriter, callbacks_id, path, client,
    286                  make_scoped_refptr(main_thread_loop), file_info));
    287 }
    288 
    289 void DidCreateSnapshotFile(
    290     int callbacks_id,
    291     base::MessageLoopProxy* main_thread_loop,
    292     const base::File::Info& file_info,
    293     const base::FilePath& platform_path,
    294     int request_id) {
    295   WebFileSystemImpl* filesystem =
    296       WebFileSystemImpl::ThreadSpecificInstance(NULL);
    297   if (!filesystem)
    298     return;
    299 
    300   WebFileSystemCallbacks callbacks = filesystem->GetCallbacks(callbacks_id);
    301   filesystem->UnregisterCallbacks(callbacks_id);
    302 
    303   WebFileInfo web_file_info;
    304   FileInfoToWebFileInfo(file_info, &web_file_info);
    305   web_file_info.platformPath = platform_path.AsUTF16Unsafe();
    306   callbacks.didCreateSnapshotFile(web_file_info);
    307 
    308   // TODO(michaeln,kinuko): Use ThreadSafeSender when Blob becomes
    309   // non-bridge model.
    310   main_thread_loop->PostTask(
    311       FROM_HERE, base::Bind(&DidReceiveSnapshotFile, request_id));
    312 }
    313 
    314 void CreateSnapshotFileCallbackAdapter(
    315     int thread_id, int callbacks_id,
    316     WaitableCallbackResults* waitable_results,
    317     base::MessageLoopProxy* main_thread_loop,
    318     const base::File::Info& file_info,
    319     const base::FilePath& platform_path,
    320     int request_id) {
    321   DispatchResultsClosure(
    322       thread_id, callbacks_id, waitable_results,
    323       base::Bind(&DidCreateSnapshotFile, callbacks_id,
    324                  make_scoped_refptr(main_thread_loop),
    325                  file_info, platform_path, request_id));
    326 }
    327 
    328 }  // namespace
    329 
    330 //-----------------------------------------------------------------------------
    331 // WebFileSystemImpl
    332 
    333 WebFileSystemImpl* WebFileSystemImpl::ThreadSpecificInstance(
    334     base::MessageLoopProxy* main_thread_loop) {
    335   if (g_webfilesystem_tls.Pointer()->Get() || !main_thread_loop)
    336     return g_webfilesystem_tls.Pointer()->Get();
    337   WebFileSystemImpl* filesystem = new WebFileSystemImpl(main_thread_loop);
    338   if (WorkerTaskRunner::Instance()->CurrentWorkerId())
    339     WorkerTaskRunner::Instance()->AddStopObserver(filesystem);
    340   return filesystem;
    341 }
    342 
    343 void WebFileSystemImpl::DeleteThreadSpecificInstance() {
    344   DCHECK(!WorkerTaskRunner::Instance()->CurrentWorkerId());
    345   if (g_webfilesystem_tls.Pointer()->Get())
    346     delete g_webfilesystem_tls.Pointer()->Get();
    347 }
    348 
    349 WebFileSystemImpl::WebFileSystemImpl(base::MessageLoopProxy* main_thread_loop)
    350     : main_thread_loop_(main_thread_loop),
    351       next_callbacks_id_(1) {
    352   g_webfilesystem_tls.Pointer()->Set(this);
    353 }
    354 
    355 WebFileSystemImpl::~WebFileSystemImpl() {
    356   g_webfilesystem_tls.Pointer()->Set(NULL);
    357 }
    358 
    359 void WebFileSystemImpl::OnWorkerRunLoopStopped() {
    360   delete this;
    361 }
    362 
    363 void WebFileSystemImpl::openFileSystem(
    364     const blink::WebURL& storage_partition,
    365     blink::WebFileSystemType type,
    366     WebFileSystemCallbacks callbacks) {
    367   int callbacks_id = RegisterCallbacks(callbacks);
    368   scoped_refptr<WaitableCallbackResults> waitable_results =
    369       MaybeCreateWaitableResults(callbacks, callbacks_id);
    370   CallDispatcherOnMainThread(
    371       main_thread_loop_.get(),
    372       &FileSystemDispatcher::OpenFileSystem,
    373       MakeTuple(GURL(storage_partition),
    374                 static_cast<fileapi::FileSystemType>(type),
    375                 base::Bind(&OpenFileSystemCallbackAdapter,
    376                            CurrentWorkerId(), callbacks_id, waitable_results),
    377                 base::Bind(&StatusCallbackAdapter,
    378                            CurrentWorkerId(), callbacks_id, waitable_results)),
    379       waitable_results.get());
    380 }
    381 
    382 void WebFileSystemImpl::resolveURL(
    383     const blink::WebURL& filesystem_url,
    384     WebFileSystemCallbacks callbacks) {
    385   int callbacks_id = RegisterCallbacks(callbacks);
    386   scoped_refptr<WaitableCallbackResults> waitable_results =
    387       MaybeCreateWaitableResults(callbacks, callbacks_id);
    388   CallDispatcherOnMainThread(
    389       main_thread_loop_.get(),
    390       &FileSystemDispatcher::ResolveURL,
    391       MakeTuple(GURL(filesystem_url),
    392                 base::Bind(&ResolveURLCallbackAdapter,
    393                            CurrentWorkerId(), callbacks_id, waitable_results),
    394                 base::Bind(&StatusCallbackAdapter,
    395                            CurrentWorkerId(), callbacks_id, waitable_results)),
    396       waitable_results.get());
    397 }
    398 
    399 void WebFileSystemImpl::deleteFileSystem(
    400     const blink::WebURL& storage_partition,
    401     blink::WebFileSystemType type,
    402     WebFileSystemCallbacks callbacks) {
    403   int callbacks_id = RegisterCallbacks(callbacks);
    404   scoped_refptr<WaitableCallbackResults> waitable_results =
    405       MaybeCreateWaitableResults(callbacks, callbacks_id);
    406   CallDispatcherOnMainThread(
    407       main_thread_loop_.get(),
    408       &FileSystemDispatcher::DeleteFileSystem,
    409       MakeTuple(GURL(storage_partition),
    410                 static_cast<fileapi::FileSystemType>(type),
    411                 base::Bind(&StatusCallbackAdapter,
    412                            CurrentWorkerId(), callbacks_id, waitable_results)),
    413       waitable_results.get());
    414 }
    415 
    416 void WebFileSystemImpl::move(
    417     const blink::WebURL& src_path,
    418     const blink::WebURL& dest_path,
    419     WebFileSystemCallbacks callbacks) {
    420   int callbacks_id = RegisterCallbacks(callbacks);
    421   scoped_refptr<WaitableCallbackResults> waitable_results =
    422       MaybeCreateWaitableResults(callbacks, callbacks_id);
    423   CallDispatcherOnMainThread(
    424       main_thread_loop_.get(),
    425       &FileSystemDispatcher::Move,
    426       MakeTuple(GURL(src_path), GURL(dest_path),
    427                 base::Bind(&StatusCallbackAdapter,
    428                            CurrentWorkerId(), callbacks_id, waitable_results)),
    429       waitable_results.get());
    430 }
    431 
    432 void WebFileSystemImpl::copy(
    433     const blink::WebURL& src_path,
    434     const blink::WebURL& dest_path,
    435     WebFileSystemCallbacks callbacks) {
    436   int callbacks_id = RegisterCallbacks(callbacks);
    437   scoped_refptr<WaitableCallbackResults> waitable_results =
    438       MaybeCreateWaitableResults(callbacks, callbacks_id);
    439   CallDispatcherOnMainThread(
    440       main_thread_loop_.get(),
    441       &FileSystemDispatcher::Copy,
    442       MakeTuple(GURL(src_path), GURL(dest_path),
    443                 base::Bind(&StatusCallbackAdapter,
    444                            CurrentWorkerId(), callbacks_id, waitable_results)),
    445       waitable_results.get());
    446 }
    447 
    448 void WebFileSystemImpl::remove(
    449     const blink::WebURL& path,
    450     WebFileSystemCallbacks callbacks) {
    451   int callbacks_id = RegisterCallbacks(callbacks);
    452   scoped_refptr<WaitableCallbackResults> waitable_results =
    453       MaybeCreateWaitableResults(callbacks, callbacks_id);
    454   CallDispatcherOnMainThread(
    455       main_thread_loop_.get(),
    456       &FileSystemDispatcher::Remove,
    457       MakeTuple(GURL(path), false /* recursive */,
    458                 base::Bind(&StatusCallbackAdapter,
    459                            CurrentWorkerId(), callbacks_id, waitable_results)),
    460       waitable_results.get());
    461 }
    462 
    463 void WebFileSystemImpl::removeRecursively(
    464     const blink::WebURL& path,
    465     WebFileSystemCallbacks callbacks) {
    466   int callbacks_id = RegisterCallbacks(callbacks);
    467   scoped_refptr<WaitableCallbackResults> waitable_results =
    468       MaybeCreateWaitableResults(callbacks, callbacks_id);
    469   CallDispatcherOnMainThread(
    470       main_thread_loop_.get(),
    471       &FileSystemDispatcher::Remove,
    472       MakeTuple(GURL(path), true /* recursive */,
    473                 base::Bind(&StatusCallbackAdapter,
    474                            CurrentWorkerId(), callbacks_id, waitable_results)),
    475       waitable_results.get());
    476 }
    477 
    478 void WebFileSystemImpl::readMetadata(
    479     const blink::WebURL& path,
    480     WebFileSystemCallbacks callbacks) {
    481   int callbacks_id = RegisterCallbacks(callbacks);
    482   scoped_refptr<WaitableCallbackResults> waitable_results =
    483       MaybeCreateWaitableResults(callbacks, callbacks_id);
    484   CallDispatcherOnMainThread(
    485       main_thread_loop_.get(),
    486       &FileSystemDispatcher::ReadMetadata,
    487       MakeTuple(GURL(path),
    488                 base::Bind(&ReadMetadataCallbackAdapter,
    489                            CurrentWorkerId(), callbacks_id, waitable_results),
    490                 base::Bind(&StatusCallbackAdapter,
    491                            CurrentWorkerId(), callbacks_id, waitable_results)),
    492       waitable_results.get());
    493 }
    494 
    495 void WebFileSystemImpl::createFile(
    496     const blink::WebURL& path,
    497     bool exclusive,
    498     WebFileSystemCallbacks callbacks) {
    499   int callbacks_id = RegisterCallbacks(callbacks);
    500   scoped_refptr<WaitableCallbackResults> waitable_results =
    501       MaybeCreateWaitableResults(callbacks, callbacks_id);
    502   CallDispatcherOnMainThread(
    503       main_thread_loop_.get(),
    504       &FileSystemDispatcher::CreateFile,
    505       MakeTuple(GURL(path), exclusive,
    506                 base::Bind(&StatusCallbackAdapter,
    507                            CurrentWorkerId(), callbacks_id, waitable_results)),
    508       waitable_results.get());
    509 }
    510 
    511 void WebFileSystemImpl::createDirectory(
    512     const blink::WebURL& path,
    513     bool exclusive,
    514     WebFileSystemCallbacks callbacks) {
    515   int callbacks_id = RegisterCallbacks(callbacks);
    516   scoped_refptr<WaitableCallbackResults> waitable_results =
    517       MaybeCreateWaitableResults(callbacks, callbacks_id);
    518   CallDispatcherOnMainThread(
    519       main_thread_loop_.get(),
    520       &FileSystemDispatcher::CreateDirectory,
    521       MakeTuple(GURL(path), exclusive, false /* recursive */,
    522                 base::Bind(&StatusCallbackAdapter,
    523                            CurrentWorkerId(), callbacks_id, waitable_results)),
    524       waitable_results.get());
    525 }
    526 
    527 void WebFileSystemImpl::fileExists(
    528     const blink::WebURL& path,
    529     WebFileSystemCallbacks callbacks) {
    530   int callbacks_id = RegisterCallbacks(callbacks);
    531   scoped_refptr<WaitableCallbackResults> waitable_results =
    532       MaybeCreateWaitableResults(callbacks, callbacks_id);
    533   CallDispatcherOnMainThread(
    534       main_thread_loop_.get(),
    535       &FileSystemDispatcher::Exists,
    536       MakeTuple(GURL(path), false /* directory */,
    537                 base::Bind(&StatusCallbackAdapter,
    538                            CurrentWorkerId(), callbacks_id, waitable_results)),
    539       waitable_results.get());
    540 }
    541 
    542 void WebFileSystemImpl::directoryExists(
    543     const blink::WebURL& path,
    544     WebFileSystemCallbacks callbacks) {
    545   int callbacks_id = RegisterCallbacks(callbacks);
    546   scoped_refptr<WaitableCallbackResults> waitable_results =
    547       MaybeCreateWaitableResults(callbacks, callbacks_id);
    548   CallDispatcherOnMainThread(
    549       main_thread_loop_.get(),
    550       &FileSystemDispatcher::Exists,
    551       MakeTuple(GURL(path), true /* directory */,
    552                 base::Bind(&StatusCallbackAdapter,
    553                            CurrentWorkerId(), callbacks_id, waitable_results)),
    554       waitable_results.get());
    555 }
    556 
    557 int WebFileSystemImpl::readDirectory(
    558     const blink::WebURL& path,
    559     WebFileSystemCallbacks callbacks) {
    560   int callbacks_id = RegisterCallbacks(callbacks);
    561   scoped_refptr<WaitableCallbackResults> waitable_results =
    562       MaybeCreateWaitableResults(callbacks, callbacks_id);
    563   CallDispatcherOnMainThread(
    564       main_thread_loop_.get(),
    565       &FileSystemDispatcher::ReadDirectory,
    566       MakeTuple(GURL(path),
    567                 base::Bind(&ReadDirectoryCallbackAdapter,
    568                            CurrentWorkerId(), callbacks_id, waitable_results),
    569                 base::Bind(&StatusCallbackAdapter,
    570                            CurrentWorkerId(), callbacks_id, waitable_results)),
    571       waitable_results.get());
    572   return callbacks_id;
    573 }
    574 
    575 void WebFileSystemImpl::createFileWriter(
    576     const WebURL& path,
    577     blink::WebFileWriterClient* client,
    578     WebFileSystemCallbacks callbacks) {
    579   int callbacks_id = RegisterCallbacks(callbacks);
    580   scoped_refptr<WaitableCallbackResults> waitable_results =
    581       MaybeCreateWaitableResults(callbacks, callbacks_id);
    582   CallDispatcherOnMainThread(
    583       main_thread_loop_.get(),
    584       &FileSystemDispatcher::ReadMetadata,
    585       MakeTuple(GURL(path),
    586                 base::Bind(&CreateFileWriterCallbackAdapter,
    587                            CurrentWorkerId(), callbacks_id, waitable_results,
    588                            main_thread_loop_, GURL(path), client),
    589                 base::Bind(&StatusCallbackAdapter,
    590                            CurrentWorkerId(), callbacks_id, waitable_results)),
    591       waitable_results.get());
    592 }
    593 
    594 void WebFileSystemImpl::createSnapshotFileAndReadMetadata(
    595     const blink::WebURL& path,
    596     WebFileSystemCallbacks callbacks) {
    597   int callbacks_id = RegisterCallbacks(callbacks);
    598   scoped_refptr<WaitableCallbackResults> waitable_results =
    599       MaybeCreateWaitableResults(callbacks, callbacks_id);
    600   CallDispatcherOnMainThread(
    601       main_thread_loop_.get(),
    602       &FileSystemDispatcher::CreateSnapshotFile,
    603       MakeTuple(GURL(path),
    604                 base::Bind(&CreateSnapshotFileCallbackAdapter,
    605                            CurrentWorkerId(), callbacks_id, waitable_results,
    606                            main_thread_loop_),
    607                 base::Bind(&StatusCallbackAdapter,
    608                            CurrentWorkerId(), callbacks_id, waitable_results)),
    609       waitable_results.get());
    610 }
    611 
    612 bool WebFileSystemImpl::waitForAdditionalResult(int callbacksId) {
    613   WaitableCallbackResultsMap::iterator found =
    614       waitable_results_.find(callbacksId);
    615   if (found == waitable_results_.end())
    616     return false;
    617 
    618   found->second->WaitAndRun();
    619   return true;
    620 }
    621 
    622 int WebFileSystemImpl::RegisterCallbacks(
    623     const WebFileSystemCallbacks& callbacks) {
    624   DCHECK(CalledOnValidThread());
    625   int id = next_callbacks_id_++;
    626   callbacks_[id] = callbacks;
    627   return id;
    628 }
    629 
    630 WebFileSystemCallbacks WebFileSystemImpl::GetCallbacks(int callbacks_id) {
    631   DCHECK(CalledOnValidThread());
    632   CallbacksMap::iterator found = callbacks_.find(callbacks_id);
    633   DCHECK(found != callbacks_.end());
    634   return found->second;
    635 }
    636 
    637 void WebFileSystemImpl::UnregisterCallbacks(int callbacks_id) {
    638   DCHECK(CalledOnValidThread());
    639   CallbacksMap::iterator found = callbacks_.find(callbacks_id);
    640   DCHECK(found != callbacks_.end());
    641   callbacks_.erase(found);
    642 
    643   waitable_results_.erase(callbacks_id);
    644 }
    645 
    646 WaitableCallbackResults* WebFileSystemImpl::MaybeCreateWaitableResults(
    647     const WebFileSystemCallbacks& callbacks, int callbacks_id) {
    648   if (!callbacks.shouldBlockUntilCompletion())
    649     return NULL;
    650   WaitableCallbackResults* results = new WaitableCallbackResults();
    651   waitable_results_[callbacks_id] = results;
    652   return results;
    653 }
    654 
    655 }  // namespace content
    656