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/child_thread.h"
     15 #include "content/child/file_info_util.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 "storage/common/fileapi/directory_entry.h"
     21 #include "storage/common/fileapi/file_system_util.h"
     22 #include "third_party/WebKit/public/platform/WebFileInfo.h"
     23 #include "third_party/WebKit/public/platform/WebFileSystemCallbacks.h"
     24 #include "third_party/WebKit/public/platform/WebString.h"
     25 #include "third_party/WebKit/public/platform/WebURL.h"
     26 #include "third_party/WebKit/public/web/WebHeap.h"
     27 #include "url/gurl.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 // Bridging functions that convert the arguments into Blink objects
    127 // (e.g. WebFileInfo, WebString, WebVector<WebFileSystemEntry>)
    128 // and call WebFileSystemCallbacks's methods.
    129 // These are called by RunCallbacks after crossing threads to ensure
    130 // thread safety, because the Blink objects cannot be passed across
    131 // threads by base::Bind().
    132 void DidSucceed(WebFileSystemCallbacks* callbacks) {
    133   callbacks->didSucceed();
    134 }
    135 
    136 void DidReadMetadata(const base::File::Info& file_info,
    137                      WebFileSystemCallbacks* callbacks) {
    138   WebFileInfo web_file_info;
    139   FileInfoToWebFileInfo(file_info, &web_file_info);
    140   callbacks->didReadMetadata(web_file_info);
    141 }
    142 
    143 void DidReadDirectory(const std::vector<storage::DirectoryEntry>& entries,
    144                       bool has_more,
    145                       WebFileSystemCallbacks* callbacks) {
    146   WebVector<WebFileSystemEntry> file_system_entries(entries.size());
    147   for (size_t i = 0; i < entries.size(); ++i) {
    148     file_system_entries[i].name =
    149         base::FilePath(entries[i].name).AsUTF16Unsafe();
    150     file_system_entries[i].isDirectory = entries[i].is_directory;
    151   }
    152   callbacks->didReadDirectory(file_system_entries, has_more);
    153 }
    154 
    155 void DidOpenFileSystem(const base::string16& name, const GURL& root,
    156                        WebFileSystemCallbacks* callbacks) {
    157   callbacks->didOpenFileSystem(name, root);
    158 }
    159 
    160 void DidResolveURL(const base::string16& name,
    161                    const GURL& root_url,
    162                    storage::FileSystemType mount_type,
    163                    const base::string16& file_path,
    164                    bool is_directory,
    165                    WebFileSystemCallbacks* callbacks) {
    166   callbacks->didResolveURL(
    167       name,
    168       root_url,
    169       static_cast<blink::WebFileSystemType>(mount_type),
    170       file_path,
    171       is_directory);
    172 }
    173 
    174 void DidFail(base::File::Error error, WebFileSystemCallbacks* callbacks) {
    175   callbacks->didFail(storage::FileErrorToWebFileError(error));
    176 }
    177 
    178 // Run WebFileSystemCallbacks's |method| with |params|.
    179 void RunCallbacks(
    180     int callbacks_id,
    181     const base::Callback<void(WebFileSystemCallbacks*)>& callback,
    182     CallbacksUnregisterMode callbacks_unregister_mode) {
    183   WebFileSystemImpl* filesystem =
    184       WebFileSystemImpl::ThreadSpecificInstance(NULL);
    185   if (!filesystem)
    186     return;
    187   WebFileSystemCallbacks callbacks = filesystem->GetCallbacks(callbacks_id);
    188   if (callbacks_unregister_mode == UNREGISTER_CALLBACKS)
    189     filesystem->UnregisterCallbacks(callbacks_id);
    190   callback.Run(&callbacks);
    191 }
    192 
    193 void DispatchResultsClosure(int thread_id, int callbacks_id,
    194                             WaitableCallbackResults* waitable_results,
    195                             const base::Closure& results_closure) {
    196   if (thread_id != CurrentWorkerId()) {
    197     if (waitable_results) {
    198       // If someone is waiting, this should result in running the closure.
    199       waitable_results->AddResultsAndSignal(results_closure);
    200       // In case no one is waiting, post a task to run the closure.
    201       WorkerTaskRunner::Instance()->PostTask(
    202           thread_id,
    203           base::Bind(&WaitableCallbackResults::Run,
    204                      make_scoped_refptr(waitable_results)));
    205       return;
    206     }
    207     WorkerTaskRunner::Instance()->PostTask(thread_id, results_closure);
    208     return;
    209   }
    210   results_closure.Run();
    211 }
    212 
    213 void CallbackFileSystemCallbacks(
    214     int thread_id, int callbacks_id,
    215     WaitableCallbackResults* waitable_results,
    216     const base::Callback<void(WebFileSystemCallbacks*)>& callback,
    217     CallbacksUnregisterMode callbacksunregister_mode) {
    218   DispatchResultsClosure(
    219       thread_id, callbacks_id, waitable_results,
    220       base::Bind(&RunCallbacks, callbacks_id, callback,
    221                  callbacksunregister_mode));
    222 }
    223 
    224 //-----------------------------------------------------------------------------
    225 // Callback adapters. Callbacks must be called on the original calling thread,
    226 // so these callback adapters relay back the results to the calling thread
    227 // if necessary.
    228 
    229 void OpenFileSystemCallbackAdapter(
    230     int thread_id, int callbacks_id,
    231     WaitableCallbackResults* waitable_results,
    232     const std::string& name, const GURL& root) {
    233   CallbackFileSystemCallbacks(
    234       thread_id, callbacks_id, waitable_results,
    235       base::Bind(&DidOpenFileSystem, base::UTF8ToUTF16(name), root),
    236       UNREGISTER_CALLBACKS);
    237 }
    238 
    239 void ResolveURLCallbackAdapter(int thread_id,
    240                                int callbacks_id,
    241                                WaitableCallbackResults* waitable_results,
    242                                const storage::FileSystemInfo& info,
    243                                const base::FilePath& file_path,
    244                                bool is_directory) {
    245   base::FilePath normalized_path(
    246       storage::VirtualPath::GetNormalizedFilePath(file_path));
    247   CallbackFileSystemCallbacks(
    248       thread_id, callbacks_id, waitable_results,
    249       base::Bind(&DidResolveURL, base::UTF8ToUTF16(info.name), info.root_url,
    250                  info.mount_type,
    251                  normalized_path.AsUTF16Unsafe(), is_directory),
    252       UNREGISTER_CALLBACKS);
    253 }
    254 
    255 void StatusCallbackAdapter(int thread_id, int callbacks_id,
    256                            WaitableCallbackResults* waitable_results,
    257                            base::File::Error error) {
    258   if (error == base::File::FILE_OK) {
    259     CallbackFileSystemCallbacks(
    260         thread_id, callbacks_id, waitable_results,
    261         base::Bind(&DidSucceed),
    262         UNREGISTER_CALLBACKS);
    263   } else {
    264     CallbackFileSystemCallbacks(
    265         thread_id, callbacks_id, waitable_results,
    266         base::Bind(&DidFail, error),
    267         UNREGISTER_CALLBACKS);
    268   }
    269 }
    270 
    271 void ReadMetadataCallbackAdapter(int thread_id, int callbacks_id,
    272                                  WaitableCallbackResults* waitable_results,
    273                                  const base::File::Info& file_info) {
    274   CallbackFileSystemCallbacks(
    275       thread_id, callbacks_id, waitable_results,
    276       base::Bind(&DidReadMetadata, file_info),
    277       UNREGISTER_CALLBACKS);
    278 }
    279 
    280 void ReadDirectoryCallbackAdapter(
    281     int thread_id,
    282     int callbacks_id,
    283     WaitableCallbackResults* waitable_results,
    284     const std::vector<storage::DirectoryEntry>& entries,
    285     bool has_more) {
    286   CallbackFileSystemCallbacks(
    287       thread_id, callbacks_id, waitable_results,
    288       base::Bind(&DidReadDirectory, entries, has_more),
    289       has_more ? DO_NOT_UNREGISTER_CALLBACKS : UNREGISTER_CALLBACKS);
    290 }
    291 
    292 void DidCreateFileWriter(
    293     int callbacks_id,
    294     const GURL& path,
    295     blink::WebFileWriterClient* client,
    296     base::MessageLoopProxy* main_thread_loop,
    297     const base::File::Info& file_info) {
    298   WebFileSystemImpl* filesystem =
    299       WebFileSystemImpl::ThreadSpecificInstance(NULL);
    300   if (!filesystem)
    301     return;
    302 
    303   WebFileSystemCallbacks callbacks = filesystem->GetCallbacks(callbacks_id);
    304   filesystem->UnregisterCallbacks(callbacks_id);
    305 
    306   if (file_info.is_directory || file_info.size < 0) {
    307     callbacks.didFail(blink::WebFileErrorInvalidState);
    308     return;
    309   }
    310   WebFileWriterImpl::Type type =
    311       callbacks.shouldBlockUntilCompletion() ?
    312           WebFileWriterImpl::TYPE_SYNC : WebFileWriterImpl::TYPE_ASYNC;
    313   callbacks.didCreateFileWriter(
    314       new WebFileWriterImpl(path, client, type, main_thread_loop),
    315       file_info.size);
    316 }
    317 
    318 void CreateFileWriterCallbackAdapter(
    319     int thread_id, int callbacks_id,
    320     WaitableCallbackResults* waitable_results,
    321     base::MessageLoopProxy* main_thread_loop,
    322     const GURL& path,
    323     blink::WebFileWriterClient* client,
    324     const base::File::Info& file_info) {
    325   DispatchResultsClosure(
    326       thread_id, callbacks_id, waitable_results,
    327       base::Bind(&DidCreateFileWriter, callbacks_id, path, client,
    328                  make_scoped_refptr(main_thread_loop), file_info));
    329 }
    330 
    331 void DidCreateSnapshotFile(
    332     int callbacks_id,
    333     base::MessageLoopProxy* main_thread_loop,
    334     const base::File::Info& file_info,
    335     const base::FilePath& platform_path,
    336     int request_id) {
    337   WebFileSystemImpl* filesystem =
    338       WebFileSystemImpl::ThreadSpecificInstance(NULL);
    339   if (!filesystem)
    340     return;
    341 
    342   WebFileSystemCallbacks callbacks = filesystem->GetCallbacks(callbacks_id);
    343   filesystem->UnregisterCallbacks(callbacks_id);
    344 
    345   WebFileInfo web_file_info;
    346   FileInfoToWebFileInfo(file_info, &web_file_info);
    347   web_file_info.platformPath = platform_path.AsUTF16Unsafe();
    348   callbacks.didCreateSnapshotFile(web_file_info);
    349 
    350   // TODO(michaeln,kinuko): Use ThreadSafeSender when Blob becomes
    351   // non-bridge model.
    352   main_thread_loop->PostTask(
    353       FROM_HERE, base::Bind(&DidReceiveSnapshotFile, request_id));
    354 }
    355 
    356 void CreateSnapshotFileCallbackAdapter(
    357     int thread_id, int callbacks_id,
    358     WaitableCallbackResults* waitable_results,
    359     base::MessageLoopProxy* main_thread_loop,
    360     const base::File::Info& file_info,
    361     const base::FilePath& platform_path,
    362     int request_id) {
    363   DispatchResultsClosure(
    364       thread_id, callbacks_id, waitable_results,
    365       base::Bind(&DidCreateSnapshotFile, callbacks_id,
    366                  make_scoped_refptr(main_thread_loop),
    367                  file_info, platform_path, request_id));
    368 }
    369 
    370 }  // namespace
    371 
    372 //-----------------------------------------------------------------------------
    373 // WebFileSystemImpl
    374 
    375 WebFileSystemImpl* WebFileSystemImpl::ThreadSpecificInstance(
    376     base::MessageLoopProxy* main_thread_loop) {
    377   if (g_webfilesystem_tls.Pointer()->Get() || !main_thread_loop)
    378     return g_webfilesystem_tls.Pointer()->Get();
    379   WebFileSystemImpl* filesystem = new WebFileSystemImpl(main_thread_loop);
    380   if (WorkerTaskRunner::Instance()->CurrentWorkerId())
    381     WorkerTaskRunner::Instance()->AddStopObserver(filesystem);
    382   return filesystem;
    383 }
    384 
    385 void WebFileSystemImpl::DeleteThreadSpecificInstance() {
    386   DCHECK(!WorkerTaskRunner::Instance()->CurrentWorkerId());
    387   if (g_webfilesystem_tls.Pointer()->Get())
    388     delete g_webfilesystem_tls.Pointer()->Get();
    389 }
    390 
    391 WebFileSystemImpl::WebFileSystemImpl(base::MessageLoopProxy* main_thread_loop)
    392     : main_thread_loop_(main_thread_loop),
    393       next_callbacks_id_(1) {
    394   g_webfilesystem_tls.Pointer()->Set(this);
    395 }
    396 
    397 WebFileSystemImpl::~WebFileSystemImpl() {
    398   g_webfilesystem_tls.Pointer()->Set(NULL);
    399 }
    400 
    401 void WebFileSystemImpl::OnWorkerRunLoopStopped() {
    402   delete this;
    403 }
    404 
    405 void WebFileSystemImpl::openFileSystem(
    406     const blink::WebURL& storage_partition,
    407     blink::WebFileSystemType type,
    408     WebFileSystemCallbacks callbacks) {
    409   int callbacks_id = RegisterCallbacks(callbacks);
    410   scoped_refptr<WaitableCallbackResults> waitable_results =
    411       MaybeCreateWaitableResults(callbacks, callbacks_id);
    412   CallDispatcherOnMainThread(
    413       main_thread_loop_.get(),
    414       &FileSystemDispatcher::OpenFileSystem,
    415       MakeTuple(GURL(storage_partition),
    416                 static_cast<storage::FileSystemType>(type),
    417                 base::Bind(&OpenFileSystemCallbackAdapter,
    418                            CurrentWorkerId(),
    419                            callbacks_id,
    420                            waitable_results),
    421                 base::Bind(&StatusCallbackAdapter,
    422                            CurrentWorkerId(),
    423                            callbacks_id,
    424                            waitable_results)),
    425       waitable_results.get());
    426 }
    427 
    428 void WebFileSystemImpl::resolveURL(
    429     const blink::WebURL& filesystem_url,
    430     WebFileSystemCallbacks callbacks) {
    431   int callbacks_id = RegisterCallbacks(callbacks);
    432   scoped_refptr<WaitableCallbackResults> waitable_results =
    433       MaybeCreateWaitableResults(callbacks, callbacks_id);
    434   CallDispatcherOnMainThread(
    435       main_thread_loop_.get(),
    436       &FileSystemDispatcher::ResolveURL,
    437       MakeTuple(GURL(filesystem_url),
    438                 base::Bind(&ResolveURLCallbackAdapter,
    439                            CurrentWorkerId(), callbacks_id, waitable_results),
    440                 base::Bind(&StatusCallbackAdapter,
    441                            CurrentWorkerId(), callbacks_id, waitable_results)),
    442       waitable_results.get());
    443 }
    444 
    445 void WebFileSystemImpl::deleteFileSystem(
    446     const blink::WebURL& storage_partition,
    447     blink::WebFileSystemType type,
    448     WebFileSystemCallbacks callbacks) {
    449   int callbacks_id = RegisterCallbacks(callbacks);
    450   scoped_refptr<WaitableCallbackResults> waitable_results =
    451       MaybeCreateWaitableResults(callbacks, callbacks_id);
    452   CallDispatcherOnMainThread(
    453       main_thread_loop_.get(),
    454       &FileSystemDispatcher::DeleteFileSystem,
    455       MakeTuple(GURL(storage_partition),
    456                 static_cast<storage::FileSystemType>(type),
    457                 base::Bind(&StatusCallbackAdapter,
    458                            CurrentWorkerId(),
    459                            callbacks_id,
    460                            waitable_results)),
    461       waitable_results.get());
    462 }
    463 
    464 void WebFileSystemImpl::move(
    465     const blink::WebURL& src_path,
    466     const blink::WebURL& dest_path,
    467     WebFileSystemCallbacks callbacks) {
    468   int callbacks_id = RegisterCallbacks(callbacks);
    469   scoped_refptr<WaitableCallbackResults> waitable_results =
    470       MaybeCreateWaitableResults(callbacks, callbacks_id);
    471   CallDispatcherOnMainThread(
    472       main_thread_loop_.get(),
    473       &FileSystemDispatcher::Move,
    474       MakeTuple(GURL(src_path), GURL(dest_path),
    475                 base::Bind(&StatusCallbackAdapter,
    476                            CurrentWorkerId(), callbacks_id, waitable_results)),
    477       waitable_results.get());
    478 }
    479 
    480 void WebFileSystemImpl::copy(
    481     const blink::WebURL& src_path,
    482     const blink::WebURL& dest_path,
    483     WebFileSystemCallbacks callbacks) {
    484   int callbacks_id = RegisterCallbacks(callbacks);
    485   scoped_refptr<WaitableCallbackResults> waitable_results =
    486       MaybeCreateWaitableResults(callbacks, callbacks_id);
    487   CallDispatcherOnMainThread(
    488       main_thread_loop_.get(),
    489       &FileSystemDispatcher::Copy,
    490       MakeTuple(GURL(src_path), GURL(dest_path),
    491                 base::Bind(&StatusCallbackAdapter,
    492                            CurrentWorkerId(), callbacks_id, waitable_results)),
    493       waitable_results.get());
    494 }
    495 
    496 void WebFileSystemImpl::remove(
    497     const blink::WebURL& path,
    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::Remove,
    505       MakeTuple(GURL(path), false /* recursive */,
    506                 base::Bind(&StatusCallbackAdapter,
    507                            CurrentWorkerId(), callbacks_id, waitable_results)),
    508       waitable_results.get());
    509 }
    510 
    511 void WebFileSystemImpl::removeRecursively(
    512     const blink::WebURL& path,
    513     WebFileSystemCallbacks callbacks) {
    514   int callbacks_id = RegisterCallbacks(callbacks);
    515   scoped_refptr<WaitableCallbackResults> waitable_results =
    516       MaybeCreateWaitableResults(callbacks, callbacks_id);
    517   CallDispatcherOnMainThread(
    518       main_thread_loop_.get(),
    519       &FileSystemDispatcher::Remove,
    520       MakeTuple(GURL(path), true /* recursive */,
    521                 base::Bind(&StatusCallbackAdapter,
    522                            CurrentWorkerId(), callbacks_id, waitable_results)),
    523       waitable_results.get());
    524 }
    525 
    526 void WebFileSystemImpl::readMetadata(
    527     const blink::WebURL& path,
    528     WebFileSystemCallbacks callbacks) {
    529   int callbacks_id = RegisterCallbacks(callbacks);
    530   scoped_refptr<WaitableCallbackResults> waitable_results =
    531       MaybeCreateWaitableResults(callbacks, callbacks_id);
    532   CallDispatcherOnMainThread(
    533       main_thread_loop_.get(),
    534       &FileSystemDispatcher::ReadMetadata,
    535       MakeTuple(GURL(path),
    536                 base::Bind(&ReadMetadataCallbackAdapter,
    537                            CurrentWorkerId(), callbacks_id, waitable_results),
    538                 base::Bind(&StatusCallbackAdapter,
    539                            CurrentWorkerId(), callbacks_id, waitable_results)),
    540       waitable_results.get());
    541 }
    542 
    543 void WebFileSystemImpl::createFile(
    544     const blink::WebURL& path,
    545     bool exclusive,
    546     WebFileSystemCallbacks callbacks) {
    547   int callbacks_id = RegisterCallbacks(callbacks);
    548   scoped_refptr<WaitableCallbackResults> waitable_results =
    549       MaybeCreateWaitableResults(callbacks, callbacks_id);
    550   CallDispatcherOnMainThread(
    551       main_thread_loop_.get(),
    552       &FileSystemDispatcher::CreateFile,
    553       MakeTuple(GURL(path), exclusive,
    554                 base::Bind(&StatusCallbackAdapter,
    555                            CurrentWorkerId(), callbacks_id, waitable_results)),
    556       waitable_results.get());
    557 }
    558 
    559 void WebFileSystemImpl::createDirectory(
    560     const blink::WebURL& path,
    561     bool exclusive,
    562     WebFileSystemCallbacks callbacks) {
    563   int callbacks_id = RegisterCallbacks(callbacks);
    564   scoped_refptr<WaitableCallbackResults> waitable_results =
    565       MaybeCreateWaitableResults(callbacks, callbacks_id);
    566   CallDispatcherOnMainThread(
    567       main_thread_loop_.get(),
    568       &FileSystemDispatcher::CreateDirectory,
    569       MakeTuple(GURL(path), exclusive, false /* recursive */,
    570                 base::Bind(&StatusCallbackAdapter,
    571                            CurrentWorkerId(), callbacks_id, waitable_results)),
    572       waitable_results.get());
    573 }
    574 
    575 void WebFileSystemImpl::fileExists(
    576     const blink::WebURL& path,
    577     WebFileSystemCallbacks callbacks) {
    578   int callbacks_id = RegisterCallbacks(callbacks);
    579   scoped_refptr<WaitableCallbackResults> waitable_results =
    580       MaybeCreateWaitableResults(callbacks, callbacks_id);
    581   CallDispatcherOnMainThread(
    582       main_thread_loop_.get(),
    583       &FileSystemDispatcher::Exists,
    584       MakeTuple(GURL(path), false /* directory */,
    585                 base::Bind(&StatusCallbackAdapter,
    586                            CurrentWorkerId(), callbacks_id, waitable_results)),
    587       waitable_results.get());
    588 }
    589 
    590 void WebFileSystemImpl::directoryExists(
    591     const blink::WebURL& path,
    592     WebFileSystemCallbacks callbacks) {
    593   int callbacks_id = RegisterCallbacks(callbacks);
    594   scoped_refptr<WaitableCallbackResults> waitable_results =
    595       MaybeCreateWaitableResults(callbacks, callbacks_id);
    596   CallDispatcherOnMainThread(
    597       main_thread_loop_.get(),
    598       &FileSystemDispatcher::Exists,
    599       MakeTuple(GURL(path), true /* directory */,
    600                 base::Bind(&StatusCallbackAdapter,
    601                            CurrentWorkerId(), callbacks_id, waitable_results)),
    602       waitable_results.get());
    603 }
    604 
    605 int WebFileSystemImpl::readDirectory(
    606     const blink::WebURL& path,
    607     WebFileSystemCallbacks callbacks) {
    608   int callbacks_id = RegisterCallbacks(callbacks);
    609   scoped_refptr<WaitableCallbackResults> waitable_results =
    610       MaybeCreateWaitableResults(callbacks, callbacks_id);
    611   CallDispatcherOnMainThread(
    612       main_thread_loop_.get(),
    613       &FileSystemDispatcher::ReadDirectory,
    614       MakeTuple(GURL(path),
    615                 base::Bind(&ReadDirectoryCallbackAdapter,
    616                            CurrentWorkerId(), callbacks_id, waitable_results),
    617                 base::Bind(&StatusCallbackAdapter,
    618                            CurrentWorkerId(), callbacks_id, waitable_results)),
    619       waitable_results.get());
    620   return callbacks_id;
    621 }
    622 
    623 void WebFileSystemImpl::createFileWriter(
    624     const WebURL& path,
    625     blink::WebFileWriterClient* client,
    626     WebFileSystemCallbacks callbacks) {
    627   int callbacks_id = RegisterCallbacks(callbacks);
    628   scoped_refptr<WaitableCallbackResults> waitable_results =
    629       MaybeCreateWaitableResults(callbacks, callbacks_id);
    630   CallDispatcherOnMainThread(
    631       main_thread_loop_.get(),
    632       &FileSystemDispatcher::ReadMetadata,
    633       MakeTuple(GURL(path),
    634                 base::Bind(&CreateFileWriterCallbackAdapter,
    635                            CurrentWorkerId(), callbacks_id, waitable_results,
    636                            main_thread_loop_, GURL(path), client),
    637                 base::Bind(&StatusCallbackAdapter,
    638                            CurrentWorkerId(), callbacks_id, waitable_results)),
    639       waitable_results.get());
    640 }
    641 
    642 void WebFileSystemImpl::createSnapshotFileAndReadMetadata(
    643     const blink::WebURL& path,
    644     WebFileSystemCallbacks callbacks) {
    645   int callbacks_id = RegisterCallbacks(callbacks);
    646   scoped_refptr<WaitableCallbackResults> waitable_results =
    647       MaybeCreateWaitableResults(callbacks, callbacks_id);
    648   CallDispatcherOnMainThread(
    649       main_thread_loop_.get(),
    650       &FileSystemDispatcher::CreateSnapshotFile,
    651       MakeTuple(GURL(path),
    652                 base::Bind(&CreateSnapshotFileCallbackAdapter,
    653                            CurrentWorkerId(), callbacks_id, waitable_results,
    654                            main_thread_loop_),
    655                 base::Bind(&StatusCallbackAdapter,
    656                            CurrentWorkerId(), callbacks_id, waitable_results)),
    657       waitable_results.get());
    658 }
    659 
    660 bool WebFileSystemImpl::waitForAdditionalResult(int callbacksId) {
    661   WaitableCallbackResultsMap::iterator found =
    662       waitable_results_.find(callbacksId);
    663   if (found == waitable_results_.end())
    664     return false;
    665 
    666   found->second->WaitAndRun();
    667   return true;
    668 }
    669 
    670 int WebFileSystemImpl::RegisterCallbacks(
    671     const WebFileSystemCallbacks& callbacks) {
    672   DCHECK(CalledOnValidThread());
    673   int id = next_callbacks_id_++;
    674   callbacks_[id] = callbacks;
    675   return id;
    676 }
    677 
    678 WebFileSystemCallbacks WebFileSystemImpl::GetCallbacks(int callbacks_id) {
    679   DCHECK(CalledOnValidThread());
    680   CallbacksMap::iterator found = callbacks_.find(callbacks_id);
    681   DCHECK(found != callbacks_.end());
    682   return found->second;
    683 }
    684 
    685 void WebFileSystemImpl::UnregisterCallbacks(int callbacks_id) {
    686   DCHECK(CalledOnValidThread());
    687   CallbacksMap::iterator found = callbacks_.find(callbacks_id);
    688   DCHECK(found != callbacks_.end());
    689   callbacks_.erase(found);
    690 
    691   waitable_results_.erase(callbacks_id);
    692 }
    693 
    694 WaitableCallbackResults* WebFileSystemImpl::MaybeCreateWaitableResults(
    695     const WebFileSystemCallbacks& callbacks, int callbacks_id) {
    696   if (!callbacks.shouldBlockUntilCompletion())
    697     return NULL;
    698   WaitableCallbackResults* results = new WaitableCallbackResults();
    699   waitable_results_[callbacks_id] = results;
    700   return results;
    701 }
    702 
    703 }  // namespace content
    704