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 29using blink::WebFileInfo; 30using blink::WebFileSystemCallbacks; 31using blink::WebFileSystemEntry; 32using blink::WebString; 33using blink::WebURL; 34using blink::WebVector; 35 36namespace content { 37 38class 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 81namespace { 82 83typedef WebFileSystemImpl::WaitableCallbackResults WaitableCallbackResults; 84 85base::LazyInstance<base::ThreadLocalPointer<WebFileSystemImpl> >::Leaky 86 g_webfilesystem_tls = LAZY_INSTANCE_INITIALIZER; 87 88void DidReceiveSnapshotFile(int request_id) { 89 if (ChildThread::current()) 90 ChildThread::current()->Send( 91 new FileSystemHostMsg_DidReceiveSnapshotFile(request_id)); 92} 93 94int CurrentWorkerId() { 95 return WorkerTaskRunner::Instance()->CurrentWorkerId(); 96} 97 98template <typename Method, typename Params> 99void 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 121enum 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(). 132void DidSucceed(WebFileSystemCallbacks* callbacks) { 133 callbacks->didSucceed(); 134} 135 136void 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 143void 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 155void DidOpenFileSystem(const base::string16& name, const GURL& root, 156 WebFileSystemCallbacks* callbacks) { 157 callbacks->didOpenFileSystem(name, root); 158} 159 160void 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 174void DidFail(base::File::Error error, WebFileSystemCallbacks* callbacks) { 175 callbacks->didFail(storage::FileErrorToWebFileError(error)); 176} 177 178// Run WebFileSystemCallbacks's |method| with |params|. 179void 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 193void 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 213void 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 229void 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 239void 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 255void 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 271void 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 280void 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 292void 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 318void 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 331void 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 356void 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 375WebFileSystemImpl* 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 385void WebFileSystemImpl::DeleteThreadSpecificInstance() { 386 DCHECK(!WorkerTaskRunner::Instance()->CurrentWorkerId()); 387 if (g_webfilesystem_tls.Pointer()->Get()) 388 delete g_webfilesystem_tls.Pointer()->Get(); 389} 390 391WebFileSystemImpl::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 397WebFileSystemImpl::~WebFileSystemImpl() { 398 g_webfilesystem_tls.Pointer()->Set(NULL); 399} 400 401void WebFileSystemImpl::OnWorkerRunLoopStopped() { 402 delete this; 403} 404 405void 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 428void 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 445void 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 464void 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 480void 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 496void 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 511void 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 526void 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 543void 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 559void 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 575void 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 590void 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 605int 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 623void 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 642void 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 660bool 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 670int WebFileSystemImpl::RegisterCallbacks( 671 const WebFileSystemCallbacks& callbacks) { 672 DCHECK(CalledOnValidThread()); 673 int id = next_callbacks_id_++; 674 callbacks_[id] = callbacks; 675 return id; 676} 677 678WebFileSystemCallbacks 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 685void 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 694WaitableCallbackResults* 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