1 // Copyright 2013 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "content/child/fileapi/webfilesystem_impl.h" 6 7 #include "base/bind.h" 8 #include "base/lazy_instance.h" 9 #include "base/logging.h" 10 #include "base/message_loop/message_loop_proxy.h" 11 #include "base/strings/utf_string_conversions.h" 12 #include "base/synchronization/waitable_event.h" 13 #include "base/threading/thread_local.h" 14 #include "content/child/blink_glue.h" 15 #include "content/child/child_thread.h" 16 #include "content/child/fileapi/file_system_dispatcher.h" 17 #include "content/child/fileapi/webfilewriter_impl.h" 18 #include "content/child/worker_task_runner.h" 19 #include "content/common/fileapi/file_system_messages.h" 20 #include "third_party/WebKit/public/platform/WebFileInfo.h" 21 #include "third_party/WebKit/public/platform/WebFileSystemCallbacks.h" 22 #include "third_party/WebKit/public/platform/WebString.h" 23 #include "third_party/WebKit/public/platform/WebURL.h" 24 #include "third_party/WebKit/public/web/WebHeap.h" 25 #include "url/gurl.h" 26 #include "webkit/common/fileapi/directory_entry.h" 27 #include "webkit/common/fileapi/file_system_util.h" 28 29 using blink::WebFileInfo; 30 using blink::WebFileSystemCallbacks; 31 using blink::WebFileSystemEntry; 32 using blink::WebString; 33 using blink::WebURL; 34 using blink::WebVector; 35 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 // Run WebFileSystemCallbacks's |method| with |params|. 127 template <typename Method, typename Params> 128 void RunCallbacks(int callbacks_id, Method method, const Params& params, 129 CallbacksUnregisterMode callbacks_unregister_mode) { 130 WebFileSystemImpl* filesystem = 131 WebFileSystemImpl::ThreadSpecificInstance(NULL); 132 if (!filesystem) 133 return; 134 WebFileSystemCallbacks callbacks = filesystem->GetCallbacks(callbacks_id); 135 if (callbacks_unregister_mode == UNREGISTER_CALLBACKS) 136 filesystem->UnregisterCallbacks(callbacks_id); 137 DispatchToMethod(&callbacks, method, params); 138 } 139 140 void DispatchResultsClosure(int thread_id, int callbacks_id, 141 WaitableCallbackResults* waitable_results, 142 const base::Closure& results_closure) { 143 if (thread_id != CurrentWorkerId()) { 144 if (waitable_results) { 145 // If someone is waiting, this should result in running the closure. 146 waitable_results->AddResultsAndSignal(results_closure); 147 // In case no one is waiting, post a task to run the closure. 148 WorkerTaskRunner::Instance()->PostTask( 149 thread_id, 150 base::Bind(&WaitableCallbackResults::Run, 151 make_scoped_refptr(waitable_results))); 152 return; 153 } 154 WorkerTaskRunner::Instance()->PostTask(thread_id, results_closure); 155 return; 156 } 157 results_closure.Run(); 158 } 159 160 template <typename Method, typename Params> 161 void CallbackFileSystemCallbacks( 162 int thread_id, int callbacks_id, 163 WaitableCallbackResults* waitable_results, 164 Method method, const Params& params, 165 CallbacksUnregisterMode callbacks_unregister_mode) { 166 DispatchResultsClosure( 167 thread_id, callbacks_id, waitable_results, 168 base::Bind(&RunCallbacks<Method, Params>, callbacks_id, method, params, 169 callbacks_unregister_mode)); 170 } 171 172 //----------------------------------------------------------------------------- 173 // Callback adapters. Callbacks must be called on the original calling thread, 174 // so these callback adapters relay back the results to the calling thread 175 // if necessary. 176 177 void OpenFileSystemCallbackAdapter( 178 int thread_id, int callbacks_id, 179 WaitableCallbackResults* waitable_results, 180 const std::string& name, const GURL& root) { 181 CallbackFileSystemCallbacks( 182 thread_id, callbacks_id, waitable_results, 183 &WebFileSystemCallbacks::didOpenFileSystem, 184 MakeTuple(base::UTF8ToUTF16(name), root), 185 UNREGISTER_CALLBACKS); 186 } 187 188 void ResolveURLCallbackAdapter( 189 int thread_id, int callbacks_id, 190 WaitableCallbackResults* waitable_results, 191 const fileapi::FileSystemInfo& info, 192 const base::FilePath& file_path, bool is_directory) { 193 base::FilePath normalized_path( 194 fileapi::VirtualPath::GetNormalizedFilePath(file_path)); 195 CallbackFileSystemCallbacks( 196 thread_id, callbacks_id, waitable_results, 197 &WebFileSystemCallbacks::didResolveURL, 198 MakeTuple(base::UTF8ToUTF16(info.name), info.root_url, 199 static_cast<blink::WebFileSystemType>(info.mount_type), 200 normalized_path.AsUTF16Unsafe(), is_directory), 201 UNREGISTER_CALLBACKS); 202 } 203 204 void StatusCallbackAdapter(int thread_id, int callbacks_id, 205 WaitableCallbackResults* waitable_results, 206 base::File::Error error) { 207 if (error == base::File::FILE_OK) { 208 CallbackFileSystemCallbacks( 209 thread_id, callbacks_id, waitable_results, 210 &WebFileSystemCallbacks::didSucceed, MakeTuple(), 211 UNREGISTER_CALLBACKS); 212 } else { 213 CallbackFileSystemCallbacks( 214 thread_id, callbacks_id, waitable_results, 215 &WebFileSystemCallbacks::didFail, 216 MakeTuple(fileapi::FileErrorToWebFileError(error)), 217 UNREGISTER_CALLBACKS); 218 } 219 } 220 221 void ReadMetadataCallbackAdapter(int thread_id, int callbacks_id, 222 WaitableCallbackResults* waitable_results, 223 const base::File::Info& file_info) { 224 WebFileInfo web_file_info; 225 FileInfoToWebFileInfo(file_info, &web_file_info); 226 CallbackFileSystemCallbacks( 227 thread_id, callbacks_id, waitable_results, 228 &WebFileSystemCallbacks::didReadMetadata, 229 MakeTuple(web_file_info), 230 UNREGISTER_CALLBACKS); 231 } 232 233 void ReadDirectoryCallbackAdapter( 234 int thread_id, int callbacks_id, WaitableCallbackResults* waitable_results, 235 const std::vector<fileapi::DirectoryEntry>& entries, 236 bool has_more) { 237 WebVector<WebFileSystemEntry> file_system_entries(entries.size()); 238 for (size_t i = 0; i < entries.size(); i++) { 239 file_system_entries[i].name = 240 base::FilePath(entries[i].name).AsUTF16Unsafe(); 241 file_system_entries[i].isDirectory = entries[i].is_directory; 242 } 243 CallbackFileSystemCallbacks( 244 thread_id, callbacks_id, waitable_results, 245 &WebFileSystemCallbacks::didReadDirectory, 246 MakeTuple(file_system_entries, has_more), 247 has_more ? DO_NOT_UNREGISTER_CALLBACKS : UNREGISTER_CALLBACKS); 248 } 249 250 void DidCreateFileWriter( 251 int callbacks_id, 252 const GURL& path, 253 blink::WebFileWriterClient* client, 254 base::MessageLoopProxy* main_thread_loop, 255 const base::File::Info& file_info) { 256 WebFileSystemImpl* filesystem = 257 WebFileSystemImpl::ThreadSpecificInstance(NULL); 258 if (!filesystem) 259 return; 260 261 WebFileSystemCallbacks callbacks = filesystem->GetCallbacks(callbacks_id); 262 filesystem->UnregisterCallbacks(callbacks_id); 263 264 if (file_info.is_directory || file_info.size < 0) { 265 callbacks.didFail(blink::WebFileErrorInvalidState); 266 return; 267 } 268 WebFileWriterImpl::Type type = 269 callbacks.shouldBlockUntilCompletion() ? 270 WebFileWriterImpl::TYPE_SYNC : WebFileWriterImpl::TYPE_ASYNC; 271 callbacks.didCreateFileWriter( 272 new WebFileWriterImpl(path, client, type, main_thread_loop), 273 file_info.size); 274 } 275 276 void CreateFileWriterCallbackAdapter( 277 int thread_id, int callbacks_id, 278 WaitableCallbackResults* waitable_results, 279 base::MessageLoopProxy* main_thread_loop, 280 const GURL& path, 281 blink::WebFileWriterClient* client, 282 const base::File::Info& file_info) { 283 DispatchResultsClosure( 284 thread_id, callbacks_id, waitable_results, 285 base::Bind(&DidCreateFileWriter, callbacks_id, path, client, 286 make_scoped_refptr(main_thread_loop), file_info)); 287 } 288 289 void DidCreateSnapshotFile( 290 int callbacks_id, 291 base::MessageLoopProxy* main_thread_loop, 292 const base::File::Info& file_info, 293 const base::FilePath& platform_path, 294 int request_id) { 295 WebFileSystemImpl* filesystem = 296 WebFileSystemImpl::ThreadSpecificInstance(NULL); 297 if (!filesystem) 298 return; 299 300 WebFileSystemCallbacks callbacks = filesystem->GetCallbacks(callbacks_id); 301 filesystem->UnregisterCallbacks(callbacks_id); 302 303 WebFileInfo web_file_info; 304 FileInfoToWebFileInfo(file_info, &web_file_info); 305 web_file_info.platformPath = platform_path.AsUTF16Unsafe(); 306 callbacks.didCreateSnapshotFile(web_file_info); 307 308 // TODO(michaeln,kinuko): Use ThreadSafeSender when Blob becomes 309 // non-bridge model. 310 main_thread_loop->PostTask( 311 FROM_HERE, base::Bind(&DidReceiveSnapshotFile, request_id)); 312 } 313 314 void CreateSnapshotFileCallbackAdapter( 315 int thread_id, int callbacks_id, 316 WaitableCallbackResults* waitable_results, 317 base::MessageLoopProxy* main_thread_loop, 318 const base::File::Info& file_info, 319 const base::FilePath& platform_path, 320 int request_id) { 321 DispatchResultsClosure( 322 thread_id, callbacks_id, waitable_results, 323 base::Bind(&DidCreateSnapshotFile, callbacks_id, 324 make_scoped_refptr(main_thread_loop), 325 file_info, platform_path, request_id)); 326 } 327 328 } // namespace 329 330 //----------------------------------------------------------------------------- 331 // WebFileSystemImpl 332 333 WebFileSystemImpl* WebFileSystemImpl::ThreadSpecificInstance( 334 base::MessageLoopProxy* main_thread_loop) { 335 if (g_webfilesystem_tls.Pointer()->Get() || !main_thread_loop) 336 return g_webfilesystem_tls.Pointer()->Get(); 337 WebFileSystemImpl* filesystem = new WebFileSystemImpl(main_thread_loop); 338 if (WorkerTaskRunner::Instance()->CurrentWorkerId()) 339 WorkerTaskRunner::Instance()->AddStopObserver(filesystem); 340 return filesystem; 341 } 342 343 void WebFileSystemImpl::DeleteThreadSpecificInstance() { 344 DCHECK(!WorkerTaskRunner::Instance()->CurrentWorkerId()); 345 if (g_webfilesystem_tls.Pointer()->Get()) 346 delete g_webfilesystem_tls.Pointer()->Get(); 347 } 348 349 WebFileSystemImpl::WebFileSystemImpl(base::MessageLoopProxy* main_thread_loop) 350 : main_thread_loop_(main_thread_loop), 351 next_callbacks_id_(1) { 352 g_webfilesystem_tls.Pointer()->Set(this); 353 } 354 355 WebFileSystemImpl::~WebFileSystemImpl() { 356 g_webfilesystem_tls.Pointer()->Set(NULL); 357 } 358 359 void WebFileSystemImpl::OnWorkerRunLoopStopped() { 360 delete this; 361 } 362 363 void WebFileSystemImpl::openFileSystem( 364 const blink::WebURL& storage_partition, 365 blink::WebFileSystemType type, 366 WebFileSystemCallbacks callbacks) { 367 int callbacks_id = RegisterCallbacks(callbacks); 368 scoped_refptr<WaitableCallbackResults> waitable_results = 369 MaybeCreateWaitableResults(callbacks, callbacks_id); 370 CallDispatcherOnMainThread( 371 main_thread_loop_.get(), 372 &FileSystemDispatcher::OpenFileSystem, 373 MakeTuple(GURL(storage_partition), 374 static_cast<fileapi::FileSystemType>(type), 375 base::Bind(&OpenFileSystemCallbackAdapter, 376 CurrentWorkerId(), callbacks_id, waitable_results), 377 base::Bind(&StatusCallbackAdapter, 378 CurrentWorkerId(), callbacks_id, waitable_results)), 379 waitable_results.get()); 380 } 381 382 void WebFileSystemImpl::resolveURL( 383 const blink::WebURL& filesystem_url, 384 WebFileSystemCallbacks callbacks) { 385 int callbacks_id = RegisterCallbacks(callbacks); 386 scoped_refptr<WaitableCallbackResults> waitable_results = 387 MaybeCreateWaitableResults(callbacks, callbacks_id); 388 CallDispatcherOnMainThread( 389 main_thread_loop_.get(), 390 &FileSystemDispatcher::ResolveURL, 391 MakeTuple(GURL(filesystem_url), 392 base::Bind(&ResolveURLCallbackAdapter, 393 CurrentWorkerId(), callbacks_id, waitable_results), 394 base::Bind(&StatusCallbackAdapter, 395 CurrentWorkerId(), callbacks_id, waitable_results)), 396 waitable_results.get()); 397 } 398 399 void WebFileSystemImpl::deleteFileSystem( 400 const blink::WebURL& storage_partition, 401 blink::WebFileSystemType type, 402 WebFileSystemCallbacks callbacks) { 403 int callbacks_id = RegisterCallbacks(callbacks); 404 scoped_refptr<WaitableCallbackResults> waitable_results = 405 MaybeCreateWaitableResults(callbacks, callbacks_id); 406 CallDispatcherOnMainThread( 407 main_thread_loop_.get(), 408 &FileSystemDispatcher::DeleteFileSystem, 409 MakeTuple(GURL(storage_partition), 410 static_cast<fileapi::FileSystemType>(type), 411 base::Bind(&StatusCallbackAdapter, 412 CurrentWorkerId(), callbacks_id, waitable_results)), 413 waitable_results.get()); 414 } 415 416 void WebFileSystemImpl::move( 417 const blink::WebURL& src_path, 418 const blink::WebURL& dest_path, 419 WebFileSystemCallbacks callbacks) { 420 int callbacks_id = RegisterCallbacks(callbacks); 421 scoped_refptr<WaitableCallbackResults> waitable_results = 422 MaybeCreateWaitableResults(callbacks, callbacks_id); 423 CallDispatcherOnMainThread( 424 main_thread_loop_.get(), 425 &FileSystemDispatcher::Move, 426 MakeTuple(GURL(src_path), GURL(dest_path), 427 base::Bind(&StatusCallbackAdapter, 428 CurrentWorkerId(), callbacks_id, waitable_results)), 429 waitable_results.get()); 430 } 431 432 void WebFileSystemImpl::copy( 433 const blink::WebURL& src_path, 434 const blink::WebURL& dest_path, 435 WebFileSystemCallbacks callbacks) { 436 int callbacks_id = RegisterCallbacks(callbacks); 437 scoped_refptr<WaitableCallbackResults> waitable_results = 438 MaybeCreateWaitableResults(callbacks, callbacks_id); 439 CallDispatcherOnMainThread( 440 main_thread_loop_.get(), 441 &FileSystemDispatcher::Copy, 442 MakeTuple(GURL(src_path), GURL(dest_path), 443 base::Bind(&StatusCallbackAdapter, 444 CurrentWorkerId(), callbacks_id, waitable_results)), 445 waitable_results.get()); 446 } 447 448 void WebFileSystemImpl::remove( 449 const blink::WebURL& path, 450 WebFileSystemCallbacks callbacks) { 451 int callbacks_id = RegisterCallbacks(callbacks); 452 scoped_refptr<WaitableCallbackResults> waitable_results = 453 MaybeCreateWaitableResults(callbacks, callbacks_id); 454 CallDispatcherOnMainThread( 455 main_thread_loop_.get(), 456 &FileSystemDispatcher::Remove, 457 MakeTuple(GURL(path), false /* recursive */, 458 base::Bind(&StatusCallbackAdapter, 459 CurrentWorkerId(), callbacks_id, waitable_results)), 460 waitable_results.get()); 461 } 462 463 void WebFileSystemImpl::removeRecursively( 464 const blink::WebURL& path, 465 WebFileSystemCallbacks callbacks) { 466 int callbacks_id = RegisterCallbacks(callbacks); 467 scoped_refptr<WaitableCallbackResults> waitable_results = 468 MaybeCreateWaitableResults(callbacks, callbacks_id); 469 CallDispatcherOnMainThread( 470 main_thread_loop_.get(), 471 &FileSystemDispatcher::Remove, 472 MakeTuple(GURL(path), true /* recursive */, 473 base::Bind(&StatusCallbackAdapter, 474 CurrentWorkerId(), callbacks_id, waitable_results)), 475 waitable_results.get()); 476 } 477 478 void WebFileSystemImpl::readMetadata( 479 const blink::WebURL& path, 480 WebFileSystemCallbacks callbacks) { 481 int callbacks_id = RegisterCallbacks(callbacks); 482 scoped_refptr<WaitableCallbackResults> waitable_results = 483 MaybeCreateWaitableResults(callbacks, callbacks_id); 484 CallDispatcherOnMainThread( 485 main_thread_loop_.get(), 486 &FileSystemDispatcher::ReadMetadata, 487 MakeTuple(GURL(path), 488 base::Bind(&ReadMetadataCallbackAdapter, 489 CurrentWorkerId(), callbacks_id, waitable_results), 490 base::Bind(&StatusCallbackAdapter, 491 CurrentWorkerId(), callbacks_id, waitable_results)), 492 waitable_results.get()); 493 } 494 495 void WebFileSystemImpl::createFile( 496 const blink::WebURL& path, 497 bool exclusive, 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::CreateFile, 505 MakeTuple(GURL(path), exclusive, 506 base::Bind(&StatusCallbackAdapter, 507 CurrentWorkerId(), callbacks_id, waitable_results)), 508 waitable_results.get()); 509 } 510 511 void WebFileSystemImpl::createDirectory( 512 const blink::WebURL& path, 513 bool exclusive, 514 WebFileSystemCallbacks callbacks) { 515 int callbacks_id = RegisterCallbacks(callbacks); 516 scoped_refptr<WaitableCallbackResults> waitable_results = 517 MaybeCreateWaitableResults(callbacks, callbacks_id); 518 CallDispatcherOnMainThread( 519 main_thread_loop_.get(), 520 &FileSystemDispatcher::CreateDirectory, 521 MakeTuple(GURL(path), exclusive, false /* recursive */, 522 base::Bind(&StatusCallbackAdapter, 523 CurrentWorkerId(), callbacks_id, waitable_results)), 524 waitable_results.get()); 525 } 526 527 void WebFileSystemImpl::fileExists( 528 const blink::WebURL& path, 529 WebFileSystemCallbacks callbacks) { 530 int callbacks_id = RegisterCallbacks(callbacks); 531 scoped_refptr<WaitableCallbackResults> waitable_results = 532 MaybeCreateWaitableResults(callbacks, callbacks_id); 533 CallDispatcherOnMainThread( 534 main_thread_loop_.get(), 535 &FileSystemDispatcher::Exists, 536 MakeTuple(GURL(path), false /* directory */, 537 base::Bind(&StatusCallbackAdapter, 538 CurrentWorkerId(), callbacks_id, waitable_results)), 539 waitable_results.get()); 540 } 541 542 void WebFileSystemImpl::directoryExists( 543 const blink::WebURL& path, 544 WebFileSystemCallbacks callbacks) { 545 int callbacks_id = RegisterCallbacks(callbacks); 546 scoped_refptr<WaitableCallbackResults> waitable_results = 547 MaybeCreateWaitableResults(callbacks, callbacks_id); 548 CallDispatcherOnMainThread( 549 main_thread_loop_.get(), 550 &FileSystemDispatcher::Exists, 551 MakeTuple(GURL(path), true /* directory */, 552 base::Bind(&StatusCallbackAdapter, 553 CurrentWorkerId(), callbacks_id, waitable_results)), 554 waitable_results.get()); 555 } 556 557 int WebFileSystemImpl::readDirectory( 558 const blink::WebURL& path, 559 WebFileSystemCallbacks callbacks) { 560 int callbacks_id = RegisterCallbacks(callbacks); 561 scoped_refptr<WaitableCallbackResults> waitable_results = 562 MaybeCreateWaitableResults(callbacks, callbacks_id); 563 CallDispatcherOnMainThread( 564 main_thread_loop_.get(), 565 &FileSystemDispatcher::ReadDirectory, 566 MakeTuple(GURL(path), 567 base::Bind(&ReadDirectoryCallbackAdapter, 568 CurrentWorkerId(), callbacks_id, waitable_results), 569 base::Bind(&StatusCallbackAdapter, 570 CurrentWorkerId(), callbacks_id, waitable_results)), 571 waitable_results.get()); 572 return callbacks_id; 573 } 574 575 void WebFileSystemImpl::createFileWriter( 576 const WebURL& path, 577 blink::WebFileWriterClient* client, 578 WebFileSystemCallbacks callbacks) { 579 int callbacks_id = RegisterCallbacks(callbacks); 580 scoped_refptr<WaitableCallbackResults> waitable_results = 581 MaybeCreateWaitableResults(callbacks, callbacks_id); 582 CallDispatcherOnMainThread( 583 main_thread_loop_.get(), 584 &FileSystemDispatcher::ReadMetadata, 585 MakeTuple(GURL(path), 586 base::Bind(&CreateFileWriterCallbackAdapter, 587 CurrentWorkerId(), callbacks_id, waitable_results, 588 main_thread_loop_, GURL(path), client), 589 base::Bind(&StatusCallbackAdapter, 590 CurrentWorkerId(), callbacks_id, waitable_results)), 591 waitable_results.get()); 592 } 593 594 void WebFileSystemImpl::createSnapshotFileAndReadMetadata( 595 const blink::WebURL& path, 596 WebFileSystemCallbacks callbacks) { 597 int callbacks_id = RegisterCallbacks(callbacks); 598 scoped_refptr<WaitableCallbackResults> waitable_results = 599 MaybeCreateWaitableResults(callbacks, callbacks_id); 600 CallDispatcherOnMainThread( 601 main_thread_loop_.get(), 602 &FileSystemDispatcher::CreateSnapshotFile, 603 MakeTuple(GURL(path), 604 base::Bind(&CreateSnapshotFileCallbackAdapter, 605 CurrentWorkerId(), callbacks_id, waitable_results, 606 main_thread_loop_), 607 base::Bind(&StatusCallbackAdapter, 608 CurrentWorkerId(), callbacks_id, waitable_results)), 609 waitable_results.get()); 610 } 611 612 bool WebFileSystemImpl::waitForAdditionalResult(int callbacksId) { 613 WaitableCallbackResultsMap::iterator found = 614 waitable_results_.find(callbacksId); 615 if (found == waitable_results_.end()) 616 return false; 617 618 found->second->WaitAndRun(); 619 return true; 620 } 621 622 int WebFileSystemImpl::RegisterCallbacks( 623 const WebFileSystemCallbacks& callbacks) { 624 DCHECK(CalledOnValidThread()); 625 int id = next_callbacks_id_++; 626 callbacks_[id] = callbacks; 627 return id; 628 } 629 630 WebFileSystemCallbacks WebFileSystemImpl::GetCallbacks(int callbacks_id) { 631 DCHECK(CalledOnValidThread()); 632 CallbacksMap::iterator found = callbacks_.find(callbacks_id); 633 DCHECK(found != callbacks_.end()); 634 return found->second; 635 } 636 637 void WebFileSystemImpl::UnregisterCallbacks(int callbacks_id) { 638 DCHECK(CalledOnValidThread()); 639 CallbacksMap::iterator found = callbacks_.find(callbacks_id); 640 DCHECK(found != callbacks_.end()); 641 callbacks_.erase(found); 642 643 waitable_results_.erase(callbacks_id); 644 } 645 646 WaitableCallbackResults* WebFileSystemImpl::MaybeCreateWaitableResults( 647 const WebFileSystemCallbacks& callbacks, int callbacks_id) { 648 if (!callbacks.shouldBlockUntilCompletion()) 649 return NULL; 650 WaitableCallbackResults* results = new WaitableCallbackResults(); 651 waitable_results_[callbacks_id] = results; 652 return results; 653 } 654 655 } // namespace content 656