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