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