• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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:
WaitableCallbackResults()41   WaitableCallbackResults()
42       : results_available_event_(true /* manual_reset */,
43                                  false /* initially_signaled */) {}
44 
AddResultsAndSignal(const base::Closure & results_closure)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 
WaitAndRun()51   void WaitAndRun() {
52     {
53       blink::WebHeap::SafePointScope safe_point;
54       results_available_event_.Wait();
55     }
56     Run();
57   }
58 
Run()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 
~WaitableCallbackResults()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 
DidReceiveSnapshotFile(int request_id)88 void DidReceiveSnapshotFile(int request_id) {
89   if (ChildThread::current())
90     ChildThread::current()->Send(
91         new FileSystemHostMsg_DidReceiveSnapshotFile(request_id));
92 }
93 
CurrentWorkerId()94 int CurrentWorkerId() {
95   return WorkerTaskRunner::Instance()->CurrentWorkerId();
96 }
97 
98 template <typename Method, typename Params>
CallDispatcherOnMainThread(base::MessageLoopProxy * loop,Method method,const Params & params,WaitableCallbackResults * waitable_results)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().
DidSucceed(WebFileSystemCallbacks * callbacks)132 void DidSucceed(WebFileSystemCallbacks* callbacks) {
133   callbacks->didSucceed();
134 }
135 
DidReadMetadata(const base::File::Info & file_info,WebFileSystemCallbacks * callbacks)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 
DidReadDirectory(const std::vector<storage::DirectoryEntry> & entries,bool has_more,WebFileSystemCallbacks * callbacks)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 
DidOpenFileSystem(const base::string16 & name,const GURL & root,WebFileSystemCallbacks * callbacks)155 void DidOpenFileSystem(const base::string16& name, const GURL& root,
156                        WebFileSystemCallbacks* callbacks) {
157   callbacks->didOpenFileSystem(name, root);
158 }
159 
DidResolveURL(const base::string16 & name,const GURL & root_url,storage::FileSystemType mount_type,const base::string16 & file_path,bool is_directory,WebFileSystemCallbacks * callbacks)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 
DidFail(base::File::Error error,WebFileSystemCallbacks * callbacks)174 void DidFail(base::File::Error error, WebFileSystemCallbacks* callbacks) {
175   callbacks->didFail(storage::FileErrorToWebFileError(error));
176 }
177 
178 // Run WebFileSystemCallbacks's |method| with |params|.
RunCallbacks(int callbacks_id,const base::Callback<void (WebFileSystemCallbacks *)> & callback,CallbacksUnregisterMode callbacks_unregister_mode)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 
DispatchResultsClosure(int thread_id,int callbacks_id,WaitableCallbackResults * waitable_results,const base::Closure & results_closure)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 
CallbackFileSystemCallbacks(int thread_id,int callbacks_id,WaitableCallbackResults * waitable_results,const base::Callback<void (WebFileSystemCallbacks *)> & callback,CallbacksUnregisterMode callbacksunregister_mode)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 
OpenFileSystemCallbackAdapter(int thread_id,int callbacks_id,WaitableCallbackResults * waitable_results,const std::string & name,const GURL & root)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 
ResolveURLCallbackAdapter(int thread_id,int callbacks_id,WaitableCallbackResults * waitable_results,const storage::FileSystemInfo & info,const base::FilePath & file_path,bool is_directory)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 
StatusCallbackAdapter(int thread_id,int callbacks_id,WaitableCallbackResults * waitable_results,base::File::Error error)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 
ReadMetadataCallbackAdapter(int thread_id,int callbacks_id,WaitableCallbackResults * waitable_results,const base::File::Info & file_info)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 
ReadDirectoryCallbackAdapter(int thread_id,int callbacks_id,WaitableCallbackResults * waitable_results,const std::vector<storage::DirectoryEntry> & entries,bool has_more)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 
DidCreateFileWriter(int callbacks_id,const GURL & path,blink::WebFileWriterClient * client,base::MessageLoopProxy * main_thread_loop,const base::File::Info & file_info)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 
CreateFileWriterCallbackAdapter(int thread_id,int callbacks_id,WaitableCallbackResults * waitable_results,base::MessageLoopProxy * main_thread_loop,const GURL & path,blink::WebFileWriterClient * client,const base::File::Info & file_info)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 
DidCreateSnapshotFile(int callbacks_id,base::MessageLoopProxy * main_thread_loop,const base::File::Info & file_info,const base::FilePath & platform_path,int request_id)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 
CreateSnapshotFileCallbackAdapter(int thread_id,int callbacks_id,WaitableCallbackResults * waitable_results,base::MessageLoopProxy * main_thread_loop,const base::File::Info & file_info,const base::FilePath & platform_path,int request_id)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 
ThreadSpecificInstance(base::MessageLoopProxy * main_thread_loop)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 
DeleteThreadSpecificInstance()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 
WebFileSystemImpl(base::MessageLoopProxy * main_thread_loop)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 
~WebFileSystemImpl()397 WebFileSystemImpl::~WebFileSystemImpl() {
398   g_webfilesystem_tls.Pointer()->Set(NULL);
399 }
400 
OnWorkerRunLoopStopped()401 void WebFileSystemImpl::OnWorkerRunLoopStopped() {
402   delete this;
403 }
404 
openFileSystem(const blink::WebURL & storage_partition,blink::WebFileSystemType type,WebFileSystemCallbacks callbacks)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 
resolveURL(const blink::WebURL & filesystem_url,WebFileSystemCallbacks callbacks)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 
deleteFileSystem(const blink::WebURL & storage_partition,blink::WebFileSystemType type,WebFileSystemCallbacks callbacks)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 
move(const blink::WebURL & src_path,const blink::WebURL & dest_path,WebFileSystemCallbacks callbacks)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 
copy(const blink::WebURL & src_path,const blink::WebURL & dest_path,WebFileSystemCallbacks callbacks)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 
remove(const blink::WebURL & path,WebFileSystemCallbacks callbacks)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 
removeRecursively(const blink::WebURL & path,WebFileSystemCallbacks callbacks)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 
readMetadata(const blink::WebURL & path,WebFileSystemCallbacks callbacks)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 
createFile(const blink::WebURL & path,bool exclusive,WebFileSystemCallbacks callbacks)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 
createDirectory(const blink::WebURL & path,bool exclusive,WebFileSystemCallbacks callbacks)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 
fileExists(const blink::WebURL & path,WebFileSystemCallbacks callbacks)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 
directoryExists(const blink::WebURL & path,WebFileSystemCallbacks callbacks)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 
readDirectory(const blink::WebURL & path,WebFileSystemCallbacks callbacks)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 
createFileWriter(const WebURL & path,blink::WebFileWriterClient * client,WebFileSystemCallbacks callbacks)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 
createSnapshotFileAndReadMetadata(const blink::WebURL & path,WebFileSystemCallbacks callbacks)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 
waitForAdditionalResult(int callbacksId)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 
RegisterCallbacks(const WebFileSystemCallbacks & callbacks)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 
GetCallbacks(int callbacks_id)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 
UnregisterCallbacks(int callbacks_id)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 
MaybeCreateWaitableResults(const WebFileSystemCallbacks & callbacks,int callbacks_id)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