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: 41 WaitableCallbackResults() 42 : results_available_event_(true /* manual_reset */, 43 false /* initially_signaled */) {} 44 45 void AddResultsAndSignal(const base::Closure& results_closure) { 46 base::AutoLock lock(lock_); 47 results_closures_.push_back(results_closure); 48 results_available_event_.Signal(); 49 } 50 51 void WaitAndRun() { 52 { 53 blink::WebHeap::SafePointScope safe_point; 54 results_available_event_.Wait(); 55 } 56 Run(); 57 } 58 59 void Run() { 60 std::vector<base::Closure> closures; 61 { 62 base::AutoLock lock(lock_); 63 results_closures_.swap(closures); 64 results_available_event_.Reset(); 65 } 66 for (size_t i = 0; i < closures.size(); ++i) 67 closures[i].Run(); 68 } 69 70 private: 71 friend class base::RefCountedThreadSafe<WaitableCallbackResults>; 72 73 ~WaitableCallbackResults() {} 74 75 base::Lock lock_; 76 base::WaitableEvent results_available_event_; 77 std::vector<base::Closure> results_closures_; 78 DISALLOW_COPY_AND_ASSIGN(WaitableCallbackResults); 79 }; 80 81 namespace { 82 83 typedef WebFileSystemImpl::WaitableCallbackResults WaitableCallbackResults; 84 85 base::LazyInstance<base::ThreadLocalPointer<WebFileSystemImpl> >::Leaky 86 g_webfilesystem_tls = LAZY_INSTANCE_INITIALIZER; 87 88 void DidReceiveSnapshotFile(int request_id) { 89 if (ChildThread::current()) 90 ChildThread::current()->Send( 91 new FileSystemHostMsg_DidReceiveSnapshotFile(request_id)); 92 } 93 94 int CurrentWorkerId() { 95 return WorkerTaskRunner::Instance()->CurrentWorkerId(); 96 } 97 98 template <typename Method, typename Params> 99 void CallDispatcherOnMainThread( 100 base::MessageLoopProxy* loop, 101 Method method, const Params& params, 102 WaitableCallbackResults* waitable_results) { 103 if (!loop->RunsTasksOnCurrentThread()) { 104 loop->PostTask(FROM_HERE, 105 base::Bind(&CallDispatcherOnMainThread<Method, Params>, 106 make_scoped_refptr(loop), method, params, 107 scoped_refptr<WaitableCallbackResults>())); 108 if (!waitable_results) 109 return; 110 waitable_results->WaitAndRun(); 111 } 112 if (!ChildThread::current() || 113 !ChildThread::current()->file_system_dispatcher()) 114 return; 115 116 DCHECK(!waitable_results); 117 DispatchToMethod(ChildThread::current()->file_system_dispatcher(), 118 method, params); 119 } 120 121 enum CallbacksUnregisterMode { 122 UNREGISTER_CALLBACKS, 123 DO_NOT_UNREGISTER_CALLBACKS, 124 }; 125 126 // Bridging functions that convert the arguments into Blink objects 127 // (e.g. WebFileInfo, WebString, WebVector<WebFileSystemEntry>) 128 // and call WebFileSystemCallbacks's methods. 129 // These are called by RunCallbacks after crossing threads to ensure 130 // thread safety, because the Blink objects cannot be passed across 131 // threads by base::Bind(). 132 void DidSucceed(WebFileSystemCallbacks* callbacks) { 133 callbacks->didSucceed(); 134 } 135 136 void DidReadMetadata(const base::File::Info& file_info, 137 WebFileSystemCallbacks* callbacks) { 138 WebFileInfo web_file_info; 139 FileInfoToWebFileInfo(file_info, &web_file_info); 140 callbacks->didReadMetadata(web_file_info); 141 } 142 143 void DidReadDirectory(const std::vector<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 155 void DidOpenFileSystem(const base::string16& name, const GURL& root, 156 WebFileSystemCallbacks* callbacks) { 157 callbacks->didOpenFileSystem(name, root); 158 } 159 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 174 void DidFail(base::File::Error error, WebFileSystemCallbacks* callbacks) { 175 callbacks->didFail(storage::FileErrorToWebFileError(error)); 176 } 177 178 // Run WebFileSystemCallbacks's |method| with |params|. 179 void RunCallbacks( 180 int callbacks_id, 181 const base::Callback<void(WebFileSystemCallbacks*)>& callback, 182 CallbacksUnregisterMode callbacks_unregister_mode) { 183 WebFileSystemImpl* filesystem = 184 WebFileSystemImpl::ThreadSpecificInstance(NULL); 185 if (!filesystem) 186 return; 187 WebFileSystemCallbacks callbacks = filesystem->GetCallbacks(callbacks_id); 188 if (callbacks_unregister_mode == UNREGISTER_CALLBACKS) 189 filesystem->UnregisterCallbacks(callbacks_id); 190 callback.Run(&callbacks); 191 } 192 193 void DispatchResultsClosure(int thread_id, int callbacks_id, 194 WaitableCallbackResults* waitable_results, 195 const base::Closure& results_closure) { 196 if (thread_id != CurrentWorkerId()) { 197 if (waitable_results) { 198 // If someone is waiting, this should result in running the closure. 199 waitable_results->AddResultsAndSignal(results_closure); 200 // In case no one is waiting, post a task to run the closure. 201 WorkerTaskRunner::Instance()->PostTask( 202 thread_id, 203 base::Bind(&WaitableCallbackResults::Run, 204 make_scoped_refptr(waitable_results))); 205 return; 206 } 207 WorkerTaskRunner::Instance()->PostTask(thread_id, results_closure); 208 return; 209 } 210 results_closure.Run(); 211 } 212 213 void CallbackFileSystemCallbacks( 214 int thread_id, int callbacks_id, 215 WaitableCallbackResults* waitable_results, 216 const base::Callback<void(WebFileSystemCallbacks*)>& callback, 217 CallbacksUnregisterMode callbacksunregister_mode) { 218 DispatchResultsClosure( 219 thread_id, callbacks_id, waitable_results, 220 base::Bind(&RunCallbacks, callbacks_id, callback, 221 callbacksunregister_mode)); 222 } 223 224 //----------------------------------------------------------------------------- 225 // Callback adapters. Callbacks must be called on the original calling thread, 226 // so these callback adapters relay back the results to the calling thread 227 // if necessary. 228 229 void OpenFileSystemCallbackAdapter( 230 int thread_id, int callbacks_id, 231 WaitableCallbackResults* waitable_results, 232 const std::string& name, const GURL& root) { 233 CallbackFileSystemCallbacks( 234 thread_id, callbacks_id, waitable_results, 235 base::Bind(&DidOpenFileSystem, base::UTF8ToUTF16(name), root), 236 UNREGISTER_CALLBACKS); 237 } 238 239 void ResolveURLCallbackAdapter(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 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 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 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 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 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 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 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 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 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 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 397 WebFileSystemImpl::~WebFileSystemImpl() { 398 g_webfilesystem_tls.Pointer()->Set(NULL); 399 } 400 401 void WebFileSystemImpl::OnWorkerRunLoopStopped() { 402 delete this; 403 } 404 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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