Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / content / child / fileapi / webfilesystem_impl.cc
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 "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 // 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<fileapi::DirectoryEntry>& entries,
144                       bool has_more, WebFileSystemCallbacks* callbacks) {
145   WebVector<WebFileSystemEntry> file_system_entries(entries.size());
146   for (size_t i = 0; i < entries.size(); ++i) {
147     file_system_entries[i].name =
148         base::FilePath(entries[i].name).AsUTF16Unsafe();
149     file_system_entries[i].isDirectory = entries[i].is_directory;
150   }
151   callbacks->didReadDirectory(file_system_entries, has_more);
152 }
153
154 void DidOpenFileSystem(const base::string16& name, const GURL& root,
155                        WebFileSystemCallbacks* callbacks) {
156   callbacks->didOpenFileSystem(name, root);
157 }
158
159 void DidResolveURL(
160     const base::string16& name,
161     const GURL& root_url,
162     fileapi::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(fileapi::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(
240     int thread_id, int callbacks_id,
241     WaitableCallbackResults* waitable_results,
242     const fileapi::FileSystemInfo& info,
243     const base::FilePath& file_path, bool is_directory) {
244   base::FilePath normalized_path(
245       fileapi::VirtualPath::GetNormalizedFilePath(file_path));
246   CallbackFileSystemCallbacks(
247       thread_id, callbacks_id, waitable_results,
248       base::Bind(&DidResolveURL, base::UTF8ToUTF16(info.name), info.root_url,
249                  info.mount_type,
250                  normalized_path.AsUTF16Unsafe(), is_directory),
251       UNREGISTER_CALLBACKS);
252 }
253
254 void StatusCallbackAdapter(int thread_id, int callbacks_id,
255                            WaitableCallbackResults* waitable_results,
256                            base::File::Error error) {
257   if (error == base::File::FILE_OK) {
258     CallbackFileSystemCallbacks(
259         thread_id, callbacks_id, waitable_results,
260         base::Bind(&DidSucceed),
261         UNREGISTER_CALLBACKS);
262   } else {
263     CallbackFileSystemCallbacks(
264         thread_id, callbacks_id, waitable_results,
265         base::Bind(&DidFail, error),
266         UNREGISTER_CALLBACKS);
267   }
268 }
269
270 void ReadMetadataCallbackAdapter(int thread_id, int callbacks_id,
271                                  WaitableCallbackResults* waitable_results,
272                                  const base::File::Info& file_info) {
273   CallbackFileSystemCallbacks(
274       thread_id, callbacks_id, waitable_results,
275       base::Bind(&DidReadMetadata, file_info),
276       UNREGISTER_CALLBACKS);
277 }
278
279 void ReadDirectoryCallbackAdapter(
280     int thread_id, int callbacks_id, WaitableCallbackResults* waitable_results,
281     const std::vector<fileapi::DirectoryEntry>& entries,
282     bool has_more) {
283   CallbackFileSystemCallbacks(
284       thread_id, callbacks_id, waitable_results,
285       base::Bind(&DidReadDirectory, entries, has_more),
286       has_more ? DO_NOT_UNREGISTER_CALLBACKS : UNREGISTER_CALLBACKS);
287 }
288
289 void DidCreateFileWriter(
290     int callbacks_id,
291     const GURL& path,
292     blink::WebFileWriterClient* client,
293     base::MessageLoopProxy* main_thread_loop,
294     const base::File::Info& file_info) {
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   if (file_info.is_directory || file_info.size < 0) {
304     callbacks.didFail(blink::WebFileErrorInvalidState);
305     return;
306   }
307   WebFileWriterImpl::Type type =
308       callbacks.shouldBlockUntilCompletion() ?
309           WebFileWriterImpl::TYPE_SYNC : WebFileWriterImpl::TYPE_ASYNC;
310   callbacks.didCreateFileWriter(
311       new WebFileWriterImpl(path, client, type, main_thread_loop),
312       file_info.size);
313 }
314
315 void CreateFileWriterCallbackAdapter(
316     int thread_id, int callbacks_id,
317     WaitableCallbackResults* waitable_results,
318     base::MessageLoopProxy* main_thread_loop,
319     const GURL& path,
320     blink::WebFileWriterClient* client,
321     const base::File::Info& file_info) {
322   DispatchResultsClosure(
323       thread_id, callbacks_id, waitable_results,
324       base::Bind(&DidCreateFileWriter, callbacks_id, path, client,
325                  make_scoped_refptr(main_thread_loop), file_info));
326 }
327
328 void DidCreateSnapshotFile(
329     int callbacks_id,
330     base::MessageLoopProxy* main_thread_loop,
331     const base::File::Info& file_info,
332     const base::FilePath& platform_path,
333     int request_id) {
334   WebFileSystemImpl* filesystem =
335       WebFileSystemImpl::ThreadSpecificInstance(NULL);
336   if (!filesystem)
337     return;
338
339   WebFileSystemCallbacks callbacks = filesystem->GetCallbacks(callbacks_id);
340   filesystem->UnregisterCallbacks(callbacks_id);
341
342   WebFileInfo web_file_info;
343   FileInfoToWebFileInfo(file_info, &web_file_info);
344   web_file_info.platformPath = platform_path.AsUTF16Unsafe();
345   callbacks.didCreateSnapshotFile(web_file_info);
346
347   // TODO(michaeln,kinuko): Use ThreadSafeSender when Blob becomes
348   // non-bridge model.
349   main_thread_loop->PostTask(
350       FROM_HERE, base::Bind(&DidReceiveSnapshotFile, request_id));
351 }
352
353 void CreateSnapshotFileCallbackAdapter(
354     int thread_id, int callbacks_id,
355     WaitableCallbackResults* waitable_results,
356     base::MessageLoopProxy* main_thread_loop,
357     const base::File::Info& file_info,
358     const base::FilePath& platform_path,
359     int request_id) {
360   DispatchResultsClosure(
361       thread_id, callbacks_id, waitable_results,
362       base::Bind(&DidCreateSnapshotFile, callbacks_id,
363                  make_scoped_refptr(main_thread_loop),
364                  file_info, platform_path, request_id));
365 }
366
367 }  // namespace
368
369 //-----------------------------------------------------------------------------
370 // WebFileSystemImpl
371
372 WebFileSystemImpl* WebFileSystemImpl::ThreadSpecificInstance(
373     base::MessageLoopProxy* main_thread_loop) {
374   if (g_webfilesystem_tls.Pointer()->Get() || !main_thread_loop)
375     return g_webfilesystem_tls.Pointer()->Get();
376   WebFileSystemImpl* filesystem = new WebFileSystemImpl(main_thread_loop);
377   if (WorkerTaskRunner::Instance()->CurrentWorkerId())
378     WorkerTaskRunner::Instance()->AddStopObserver(filesystem);
379   return filesystem;
380 }
381
382 void WebFileSystemImpl::DeleteThreadSpecificInstance() {
383   DCHECK(!WorkerTaskRunner::Instance()->CurrentWorkerId());
384   if (g_webfilesystem_tls.Pointer()->Get())
385     delete g_webfilesystem_tls.Pointer()->Get();
386 }
387
388 WebFileSystemImpl::WebFileSystemImpl(base::MessageLoopProxy* main_thread_loop)
389     : main_thread_loop_(main_thread_loop),
390       next_callbacks_id_(1) {
391   g_webfilesystem_tls.Pointer()->Set(this);
392 }
393
394 WebFileSystemImpl::~WebFileSystemImpl() {
395   g_webfilesystem_tls.Pointer()->Set(NULL);
396 }
397
398 void WebFileSystemImpl::OnWorkerRunLoopStopped() {
399   delete this;
400 }
401
402 void WebFileSystemImpl::openFileSystem(
403     const blink::WebURL& storage_partition,
404     blink::WebFileSystemType type,
405     WebFileSystemCallbacks callbacks) {
406   int callbacks_id = RegisterCallbacks(callbacks);
407   scoped_refptr<WaitableCallbackResults> waitable_results =
408       MaybeCreateWaitableResults(callbacks, callbacks_id);
409   CallDispatcherOnMainThread(
410       main_thread_loop_.get(),
411       &FileSystemDispatcher::OpenFileSystem,
412       MakeTuple(GURL(storage_partition),
413                 static_cast<fileapi::FileSystemType>(type),
414                 base::Bind(&OpenFileSystemCallbackAdapter,
415                            CurrentWorkerId(), callbacks_id, waitable_results),
416                 base::Bind(&StatusCallbackAdapter,
417                            CurrentWorkerId(), callbacks_id, waitable_results)),
418       waitable_results.get());
419 }
420
421 void WebFileSystemImpl::resolveURL(
422     const blink::WebURL& filesystem_url,
423     WebFileSystemCallbacks callbacks) {
424   int callbacks_id = RegisterCallbacks(callbacks);
425   scoped_refptr<WaitableCallbackResults> waitable_results =
426       MaybeCreateWaitableResults(callbacks, callbacks_id);
427   CallDispatcherOnMainThread(
428       main_thread_loop_.get(),
429       &FileSystemDispatcher::ResolveURL,
430       MakeTuple(GURL(filesystem_url),
431                 base::Bind(&ResolveURLCallbackAdapter,
432                            CurrentWorkerId(), callbacks_id, waitable_results),
433                 base::Bind(&StatusCallbackAdapter,
434                            CurrentWorkerId(), callbacks_id, waitable_results)),
435       waitable_results.get());
436 }
437
438 void WebFileSystemImpl::deleteFileSystem(
439     const blink::WebURL& storage_partition,
440     blink::WebFileSystemType type,
441     WebFileSystemCallbacks callbacks) {
442   int callbacks_id = RegisterCallbacks(callbacks);
443   scoped_refptr<WaitableCallbackResults> waitable_results =
444       MaybeCreateWaitableResults(callbacks, callbacks_id);
445   CallDispatcherOnMainThread(
446       main_thread_loop_.get(),
447       &FileSystemDispatcher::DeleteFileSystem,
448       MakeTuple(GURL(storage_partition),
449                 static_cast<fileapi::FileSystemType>(type),
450                 base::Bind(&StatusCallbackAdapter,
451                            CurrentWorkerId(), callbacks_id, waitable_results)),
452       waitable_results.get());
453 }
454
455 void WebFileSystemImpl::move(
456     const blink::WebURL& src_path,
457     const blink::WebURL& dest_path,
458     WebFileSystemCallbacks callbacks) {
459   int callbacks_id = RegisterCallbacks(callbacks);
460   scoped_refptr<WaitableCallbackResults> waitable_results =
461       MaybeCreateWaitableResults(callbacks, callbacks_id);
462   CallDispatcherOnMainThread(
463       main_thread_loop_.get(),
464       &FileSystemDispatcher::Move,
465       MakeTuple(GURL(src_path), GURL(dest_path),
466                 base::Bind(&StatusCallbackAdapter,
467                            CurrentWorkerId(), callbacks_id, waitable_results)),
468       waitable_results.get());
469 }
470
471 void WebFileSystemImpl::copy(
472     const blink::WebURL& src_path,
473     const blink::WebURL& dest_path,
474     WebFileSystemCallbacks callbacks) {
475   int callbacks_id = RegisterCallbacks(callbacks);
476   scoped_refptr<WaitableCallbackResults> waitable_results =
477       MaybeCreateWaitableResults(callbacks, callbacks_id);
478   CallDispatcherOnMainThread(
479       main_thread_loop_.get(),
480       &FileSystemDispatcher::Copy,
481       MakeTuple(GURL(src_path), GURL(dest_path),
482                 base::Bind(&StatusCallbackAdapter,
483                            CurrentWorkerId(), callbacks_id, waitable_results)),
484       waitable_results.get());
485 }
486
487 void WebFileSystemImpl::remove(
488     const blink::WebURL& path,
489     WebFileSystemCallbacks callbacks) {
490   int callbacks_id = RegisterCallbacks(callbacks);
491   scoped_refptr<WaitableCallbackResults> waitable_results =
492       MaybeCreateWaitableResults(callbacks, callbacks_id);
493   CallDispatcherOnMainThread(
494       main_thread_loop_.get(),
495       &FileSystemDispatcher::Remove,
496       MakeTuple(GURL(path), false /* recursive */,
497                 base::Bind(&StatusCallbackAdapter,
498                            CurrentWorkerId(), callbacks_id, waitable_results)),
499       waitable_results.get());
500 }
501
502 void WebFileSystemImpl::removeRecursively(
503     const blink::WebURL& path,
504     WebFileSystemCallbacks callbacks) {
505   int callbacks_id = RegisterCallbacks(callbacks);
506   scoped_refptr<WaitableCallbackResults> waitable_results =
507       MaybeCreateWaitableResults(callbacks, callbacks_id);
508   CallDispatcherOnMainThread(
509       main_thread_loop_.get(),
510       &FileSystemDispatcher::Remove,
511       MakeTuple(GURL(path), true /* recursive */,
512                 base::Bind(&StatusCallbackAdapter,
513                            CurrentWorkerId(), callbacks_id, waitable_results)),
514       waitable_results.get());
515 }
516
517 void WebFileSystemImpl::readMetadata(
518     const blink::WebURL& path,
519     WebFileSystemCallbacks callbacks) {
520   int callbacks_id = RegisterCallbacks(callbacks);
521   scoped_refptr<WaitableCallbackResults> waitable_results =
522       MaybeCreateWaitableResults(callbacks, callbacks_id);
523   CallDispatcherOnMainThread(
524       main_thread_loop_.get(),
525       &FileSystemDispatcher::ReadMetadata,
526       MakeTuple(GURL(path),
527                 base::Bind(&ReadMetadataCallbackAdapter,
528                            CurrentWorkerId(), callbacks_id, waitable_results),
529                 base::Bind(&StatusCallbackAdapter,
530                            CurrentWorkerId(), callbacks_id, waitable_results)),
531       waitable_results.get());
532 }
533
534 void WebFileSystemImpl::createFile(
535     const blink::WebURL& path,
536     bool exclusive,
537     WebFileSystemCallbacks callbacks) {
538   int callbacks_id = RegisterCallbacks(callbacks);
539   scoped_refptr<WaitableCallbackResults> waitable_results =
540       MaybeCreateWaitableResults(callbacks, callbacks_id);
541   CallDispatcherOnMainThread(
542       main_thread_loop_.get(),
543       &FileSystemDispatcher::CreateFile,
544       MakeTuple(GURL(path), exclusive,
545                 base::Bind(&StatusCallbackAdapter,
546                            CurrentWorkerId(), callbacks_id, waitable_results)),
547       waitable_results.get());
548 }
549
550 void WebFileSystemImpl::createDirectory(
551     const blink::WebURL& path,
552     bool exclusive,
553     WebFileSystemCallbacks callbacks) {
554   int callbacks_id = RegisterCallbacks(callbacks);
555   scoped_refptr<WaitableCallbackResults> waitable_results =
556       MaybeCreateWaitableResults(callbacks, callbacks_id);
557   CallDispatcherOnMainThread(
558       main_thread_loop_.get(),
559       &FileSystemDispatcher::CreateDirectory,
560       MakeTuple(GURL(path), exclusive, false /* recursive */,
561                 base::Bind(&StatusCallbackAdapter,
562                            CurrentWorkerId(), callbacks_id, waitable_results)),
563       waitable_results.get());
564 }
565
566 void WebFileSystemImpl::fileExists(
567     const blink::WebURL& path,
568     WebFileSystemCallbacks callbacks) {
569   int callbacks_id = RegisterCallbacks(callbacks);
570   scoped_refptr<WaitableCallbackResults> waitable_results =
571       MaybeCreateWaitableResults(callbacks, callbacks_id);
572   CallDispatcherOnMainThread(
573       main_thread_loop_.get(),
574       &FileSystemDispatcher::Exists,
575       MakeTuple(GURL(path), false /* directory */,
576                 base::Bind(&StatusCallbackAdapter,
577                            CurrentWorkerId(), callbacks_id, waitable_results)),
578       waitable_results.get());
579 }
580
581 void WebFileSystemImpl::directoryExists(
582     const blink::WebURL& path,
583     WebFileSystemCallbacks callbacks) {
584   int callbacks_id = RegisterCallbacks(callbacks);
585   scoped_refptr<WaitableCallbackResults> waitable_results =
586       MaybeCreateWaitableResults(callbacks, callbacks_id);
587   CallDispatcherOnMainThread(
588       main_thread_loop_.get(),
589       &FileSystemDispatcher::Exists,
590       MakeTuple(GURL(path), true /* directory */,
591                 base::Bind(&StatusCallbackAdapter,
592                            CurrentWorkerId(), callbacks_id, waitable_results)),
593       waitable_results.get());
594 }
595
596 int WebFileSystemImpl::readDirectory(
597     const blink::WebURL& path,
598     WebFileSystemCallbacks callbacks) {
599   int callbacks_id = RegisterCallbacks(callbacks);
600   scoped_refptr<WaitableCallbackResults> waitable_results =
601       MaybeCreateWaitableResults(callbacks, callbacks_id);
602   CallDispatcherOnMainThread(
603       main_thread_loop_.get(),
604       &FileSystemDispatcher::ReadDirectory,
605       MakeTuple(GURL(path),
606                 base::Bind(&ReadDirectoryCallbackAdapter,
607                            CurrentWorkerId(), callbacks_id, waitable_results),
608                 base::Bind(&StatusCallbackAdapter,
609                            CurrentWorkerId(), callbacks_id, waitable_results)),
610       waitable_results.get());
611   return callbacks_id;
612 }
613
614 void WebFileSystemImpl::createFileWriter(
615     const WebURL& path,
616     blink::WebFileWriterClient* client,
617     WebFileSystemCallbacks callbacks) {
618   int callbacks_id = RegisterCallbacks(callbacks);
619   scoped_refptr<WaitableCallbackResults> waitable_results =
620       MaybeCreateWaitableResults(callbacks, callbacks_id);
621   CallDispatcherOnMainThread(
622       main_thread_loop_.get(),
623       &FileSystemDispatcher::ReadMetadata,
624       MakeTuple(GURL(path),
625                 base::Bind(&CreateFileWriterCallbackAdapter,
626                            CurrentWorkerId(), callbacks_id, waitable_results,
627                            main_thread_loop_, GURL(path), client),
628                 base::Bind(&StatusCallbackAdapter,
629                            CurrentWorkerId(), callbacks_id, waitable_results)),
630       waitable_results.get());
631 }
632
633 void WebFileSystemImpl::createSnapshotFileAndReadMetadata(
634     const blink::WebURL& path,
635     WebFileSystemCallbacks callbacks) {
636   int callbacks_id = RegisterCallbacks(callbacks);
637   scoped_refptr<WaitableCallbackResults> waitable_results =
638       MaybeCreateWaitableResults(callbacks, callbacks_id);
639   CallDispatcherOnMainThread(
640       main_thread_loop_.get(),
641       &FileSystemDispatcher::CreateSnapshotFile,
642       MakeTuple(GURL(path),
643                 base::Bind(&CreateSnapshotFileCallbackAdapter,
644                            CurrentWorkerId(), callbacks_id, waitable_results,
645                            main_thread_loop_),
646                 base::Bind(&StatusCallbackAdapter,
647                            CurrentWorkerId(), callbacks_id, waitable_results)),
648       waitable_results.get());
649 }
650
651 bool WebFileSystemImpl::waitForAdditionalResult(int callbacksId) {
652   WaitableCallbackResultsMap::iterator found =
653       waitable_results_.find(callbacksId);
654   if (found == waitable_results_.end())
655     return false;
656
657   found->second->WaitAndRun();
658   return true;
659 }
660
661 int WebFileSystemImpl::RegisterCallbacks(
662     const WebFileSystemCallbacks& callbacks) {
663   DCHECK(CalledOnValidThread());
664   int id = next_callbacks_id_++;
665   callbacks_[id] = callbacks;
666   return id;
667 }
668
669 WebFileSystemCallbacks WebFileSystemImpl::GetCallbacks(int callbacks_id) {
670   DCHECK(CalledOnValidThread());
671   CallbacksMap::iterator found = callbacks_.find(callbacks_id);
672   DCHECK(found != callbacks_.end());
673   return found->second;
674 }
675
676 void WebFileSystemImpl::UnregisterCallbacks(int callbacks_id) {
677   DCHECK(CalledOnValidThread());
678   CallbacksMap::iterator found = callbacks_.find(callbacks_id);
679   DCHECK(found != callbacks_.end());
680   callbacks_.erase(found);
681
682   waitable_results_.erase(callbacks_id);
683 }
684
685 WaitableCallbackResults* WebFileSystemImpl::MaybeCreateWaitableResults(
686     const WebFileSystemCallbacks& callbacks, int callbacks_id) {
687   if (!callbacks.shouldBlockUntilCompletion())
688     return NULL;
689   WaitableCallbackResults* results = new WaitableCallbackResults();
690   waitable_results_[callbacks_id] = results;
691   return results;
692 }
693
694 }  // namespace content