OLD | NEW |
---|---|
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/chromeos/file_system_provider/provided_file_system.h" | 5 #include "chrome/browser/chromeos/file_system_provider/provided_file_system.h" |
6 | 6 |
7 #include <vector> | 7 #include <vector> |
8 | 8 |
9 #include "base/debug/trace_event.h" | 9 #include "base/debug/trace_event.h" |
10 #include "base/files/file.h" | 10 #include "base/files/file.h" |
(...skipping 24 matching lines...) Expand all Loading... | |
35 } // namespace net | 35 } // namespace net |
36 | 36 |
37 namespace chromeos { | 37 namespace chromeos { |
38 namespace file_system_provider { | 38 namespace file_system_provider { |
39 namespace { | 39 namespace { |
40 | 40 |
41 // Discards the result of Abort() when called from the destructor. | 41 // Discards the result of Abort() when called from the destructor. |
42 void EmptyStatusCallback(base::File::Error /* result */) { | 42 void EmptyStatusCallback(base::File::Error /* result */) { |
43 } | 43 } |
44 | 44 |
45 // Discards the error code and always calls the callback with a success. | |
46 void AlwaysSuccessCallback( | |
47 const storage::AsyncFileUtil::StatusCallback& callback, | |
48 base::File::Error /* result */) { | |
49 callback.Run(base::File::FILE_OK); | |
50 } | |
51 | |
45 } // namespace | 52 } // namespace |
46 | 53 |
47 AutoUpdater::AutoUpdater(const base::Closure& update_callback) | 54 AutoUpdater::AutoUpdater(const base::Closure& update_callback) |
48 : update_callback_(update_callback), | 55 : update_callback_(update_callback), |
49 created_callbacks_(0), | 56 created_callbacks_(0), |
50 pending_callbacks_(0) { | 57 pending_callbacks_(0) { |
51 } | 58 } |
52 | 59 |
53 base::Closure AutoUpdater::CreateCallback() { | 60 base::Closure AutoUpdater::CreateCallback() { |
54 ++created_callbacks_; | 61 ++created_callbacks_; |
(...skipping 296 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
351 if (!request_id) { | 358 if (!request_id) { |
352 callback.Run(base::File::FILE_ERROR_SECURITY); | 359 callback.Run(base::File::FILE_ERROR_SECURITY); |
353 return AbortCallback(); | 360 return AbortCallback(); |
354 } | 361 } |
355 | 362 |
356 return base::Bind( | 363 return base::Bind( |
357 &ProvidedFileSystem::Abort, weak_ptr_factory_.GetWeakPtr(), request_id); | 364 &ProvidedFileSystem::Abort, weak_ptr_factory_.GetWeakPtr(), request_id); |
358 } | 365 } |
359 | 366 |
360 ProvidedFileSystem::AbortCallback ProvidedFileSystem::ObserveDirectory( | 367 ProvidedFileSystem::AbortCallback ProvidedFileSystem::ObserveDirectory( |
368 const GURL& origin, | |
361 const base::FilePath& directory_path, | 369 const base::FilePath& directory_path, |
362 bool recursive, | 370 bool recursive, |
371 bool persistent, | |
363 const storage::AsyncFileUtil::StatusCallback& callback) { | 372 const storage::AsyncFileUtil::StatusCallback& callback) { |
364 // TODO(mtomasz): Wrap the entire method body with an asynchronous queue to | 373 // TODO(mtomasz): Wrap the entire method body with an asynchronous queue to |
365 // avoid races. | 374 // avoid races. |
366 const ObservedEntries::const_iterator it = | 375 |
367 observed_entries_.find(directory_path); | 376 if (persistent && !file_system_info_.supports_notify_tag()) { |
377 OnObserveDirectoryCompleted(origin, | |
378 directory_path, | |
379 recursive, | |
380 persistent, | |
381 callback, | |
382 base::File::FILE_ERROR_INVALID_OPERATION); | |
383 return AbortCallback(); | |
384 } | |
385 | |
386 const ObservedEntries::iterator it = observed_entries_.find(directory_path); | |
368 if (it != observed_entries_.end()) { | 387 if (it != observed_entries_.end()) { |
388 if (it->second.subscribers.find(origin) != it->second.subscribers.end()) { | |
389 OnObserveDirectoryCompleted(origin, | |
390 directory_path, | |
391 recursive, | |
392 persistent, | |
393 callback, | |
394 base::File::FILE_ERROR_EXISTS); | |
395 return AbortCallback(); | |
396 } | |
369 if (!recursive || it->second.recursive) { | 397 if (!recursive || it->second.recursive) { |
hirono
2014/10/22 06:00:35
If extension A requests with recursive=false and t
mtomasz
2014/10/24 05:48:42
After offline discussion we decided to split recur
| |
370 callback.Run(base::File::FILE_ERROR_EXISTS); | 398 OnObserveDirectoryCompleted(origin, |
399 directory_path, | |
400 recursive, | |
401 persistent, | |
402 callback, | |
403 base::File::FILE_OK); | |
371 return AbortCallback(); | 404 return AbortCallback(); |
372 } | 405 } |
373 } | 406 } |
374 | 407 |
375 const int request_id = request_manager_->CreateRequest( | 408 const int request_id = request_manager_->CreateRequest( |
376 OBSERVE_DIRECTORY, | 409 OBSERVE_DIRECTORY, |
377 scoped_ptr<RequestManager::HandlerInterface>( | 410 scoped_ptr<RequestManager::HandlerInterface>( |
378 new operations::ObserveDirectory( | 411 new operations::ObserveDirectory( |
379 event_router_, | 412 event_router_, |
380 file_system_info_, | 413 file_system_info_, |
381 directory_path, | 414 directory_path, |
382 recursive, | 415 recursive, |
383 base::Bind(&ProvidedFileSystem::OnObserveDirectoryCompleted, | 416 base::Bind(&ProvidedFileSystem::OnObserveDirectoryCompleted, |
384 weak_ptr_factory_.GetWeakPtr(), | 417 weak_ptr_factory_.GetWeakPtr(), |
418 origin, | |
385 directory_path, | 419 directory_path, |
386 recursive, | 420 recursive, |
421 persistent, | |
387 callback)))); | 422 callback)))); |
423 | |
388 if (!request_id) { | 424 if (!request_id) { |
389 callback.Run(base::File::FILE_ERROR_SECURITY); | 425 OnObserveDirectoryCompleted(origin, |
426 directory_path, | |
427 recursive, | |
428 persistent, | |
429 callback, | |
430 base::File::FILE_ERROR_SECURITY); | |
390 return AbortCallback(); | 431 return AbortCallback(); |
391 } | 432 } |
392 | 433 |
393 return base::Bind( | 434 return base::Bind( |
394 &ProvidedFileSystem::Abort, weak_ptr_factory_.GetWeakPtr(), request_id); | 435 &ProvidedFileSystem::Abort, weak_ptr_factory_.GetWeakPtr(), request_id); |
395 } | 436 } |
396 | 437 |
397 void ProvidedFileSystem::UnobserveEntry( | 438 void ProvidedFileSystem::UnobserveEntry( |
439 const GURL& origin, | |
398 const base::FilePath& entry_path, | 440 const base::FilePath& entry_path, |
399 const storage::AsyncFileUtil::StatusCallback& callback) { | 441 const storage::AsyncFileUtil::StatusCallback& callback) { |
400 const ObservedEntries::const_iterator it = observed_entries_.find(entry_path); | 442 const ObservedEntries::iterator it = observed_entries_.find(entry_path); |
401 if (it == observed_entries_.end()) { | 443 if (it == observed_entries_.end() || |
444 it->second.subscribers.find(origin) == it->second.subscribers.end()) { | |
402 callback.Run(base::File::FILE_ERROR_NOT_FOUND); | 445 callback.Run(base::File::FILE_ERROR_NOT_FOUND); |
403 return; | 446 return; |
404 } | 447 } |
405 | 448 |
406 // Delete the watcher in advance since the list of observed entries is owned | 449 // Delete the subscriber in advance, since the list of observed entries is |
407 // by the C++ layer, not by the extension. | 450 // owned by the C++ layer, not by the extension. |
408 observed_entries_.erase(it); | 451 it->second.subscribers.erase(origin); |
409 | 452 |
410 FOR_EACH_OBSERVER( | 453 FOR_EACH_OBSERVER( |
411 ProvidedFileSystemObserver, | 454 ProvidedFileSystemObserver, |
412 observers_, | 455 observers_, |
413 OnObservedEntryListChanged(file_system_info_, observed_entries_)); | 456 OnObservedEntryListChanged(file_system_info_, observed_entries_)); |
414 | 457 |
415 // TODO(mtomasz): Consider returning always an OK error code, since for the | 458 // If there are other subscribers, then do not remove the obsererver, but |
416 // callers it's important that the entry is not watched anymore. The watcher | 459 // simply return a success. |
417 // is removed even if the extension returns an error. | 460 if (it->second.subscribers.size()) { |
461 callback.Run(base::File::FILE_OK); | |
462 return; | |
463 } | |
464 | |
465 // Delete the watcher in advance. | |
466 observed_entries_.erase(it); | |
467 | |
468 // Even if the extension returns an error, the callback is called with base:: | |
469 // File::FILE_OK. The reason for that is that the observed is not watched | |
470 // anymore anyway, as it's removed in advance. | |
418 const int request_id = request_manager_->CreateRequest( | 471 const int request_id = request_manager_->CreateRequest( |
419 UNOBSERVE_ENTRY, | 472 UNOBSERVE_ENTRY, |
420 scoped_ptr<RequestManager::HandlerInterface>( | 473 scoped_ptr<RequestManager::HandlerInterface>( |
421 new operations::UnobserveEntry( | 474 new operations::UnobserveEntry( |
422 event_router_, file_system_info_, entry_path, callback))); | 475 event_router_, |
476 file_system_info_, | |
477 entry_path, | |
478 base::Bind(&AlwaysSuccessCallback, callback)))); | |
479 | |
423 if (!request_id) | 480 if (!request_id) |
424 callback.Run(base::File::FILE_ERROR_SECURITY); | 481 callback.Run(base::File::FILE_OK); |
425 } | 482 } |
426 | 483 |
427 const ProvidedFileSystemInfo& ProvidedFileSystem::GetFileSystemInfo() const { | 484 const ProvidedFileSystemInfo& ProvidedFileSystem::GetFileSystemInfo() const { |
428 return file_system_info_; | 485 return file_system_info_; |
429 } | 486 } |
430 | 487 |
431 RequestManager* ProvidedFileSystem::GetRequestManager() { | 488 RequestManager* ProvidedFileSystem::GetRequestManager() { |
432 return request_manager_.get(); | 489 return request_manager_.get(); |
433 } | 490 } |
434 | 491 |
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
499 scoped_ptr<RequestManager::HandlerInterface>( | 556 scoped_ptr<RequestManager::HandlerInterface>( |
500 new operations::Abort(event_router_, | 557 new operations::Abort(event_router_, |
501 file_system_info_, | 558 file_system_info_, |
502 operation_request_id, | 559 operation_request_id, |
503 callback)))) { | 560 callback)))) { |
504 callback.Run(base::File::FILE_ERROR_SECURITY); | 561 callback.Run(base::File::FILE_ERROR_SECURITY); |
505 } | 562 } |
506 } | 563 } |
507 | 564 |
508 void ProvidedFileSystem::OnObserveDirectoryCompleted( | 565 void ProvidedFileSystem::OnObserveDirectoryCompleted( |
566 const GURL& origin, | |
509 const base::FilePath& directory_path, | 567 const base::FilePath& directory_path, |
510 bool recursive, | 568 bool recursive, |
569 bool persistent, | |
511 const storage::AsyncFileUtil::StatusCallback& callback, | 570 const storage::AsyncFileUtil::StatusCallback& callback, |
512 base::File::Error result) { | 571 base::File::Error result) { |
513 if (result != base::File::FILE_OK) { | 572 if (result != base::File::FILE_OK) { |
514 callback.Run(result); | 573 callback.Run(result); |
515 return; | 574 return; |
516 } | 575 } |
517 | 576 |
518 observed_entries_[directory_path].entry_path = directory_path; | 577 ObservedEntry* const observed_entry = &observed_entries_[directory_path]; |
519 observed_entries_[directory_path].recursive |= recursive; | 578 observed_entry->entry_path = directory_path; |
579 observed_entry->recursive |= recursive; | |
580 observed_entry->subscribers[origin].origin = origin; | |
581 observed_entry->subscribers[origin].persistent |= persistent; | |
520 | 582 |
521 FOR_EACH_OBSERVER( | 583 FOR_EACH_OBSERVER( |
522 ProvidedFileSystemObserver, | 584 ProvidedFileSystemObserver, |
523 observers_, | 585 observers_, |
524 OnObservedEntryListChanged(file_system_info_, observed_entries_)); | 586 OnObservedEntryListChanged(file_system_info_, observed_entries_)); |
525 | 587 |
526 callback.Run(result); | 588 callback.Run(result); |
527 } | 589 } |
528 | 590 |
529 void ProvidedFileSystem::OnNotifyCompleted( | 591 void ProvidedFileSystem::OnNotifyCompleted( |
(...skipping 17 matching lines...) Expand all Loading... | |
547 if (!tag.empty() && tag == it->second.last_tag) | 609 if (!tag.empty() && tag == it->second.last_tag) |
548 LOG(ERROR) << "Tag specified, but same as the previous one."; | 610 LOG(ERROR) << "Tag specified, but same as the previous one."; |
549 | 611 |
550 it->second.last_tag = tag; | 612 it->second.last_tag = tag; |
551 | 613 |
552 FOR_EACH_OBSERVER(ProvidedFileSystemObserver, | 614 FOR_EACH_OBSERVER(ProvidedFileSystemObserver, |
553 observers_, | 615 observers_, |
554 OnObservedEntryTagUpdated(file_system_info_, it->second)); | 616 OnObservedEntryTagUpdated(file_system_info_, it->second)); |
555 | 617 |
556 // If the observed entry is deleted, then unobserve it. | 618 // If the observed entry is deleted, then unobserve it. |
557 if (change_type == ProvidedFileSystemObserver::DELETED) | 619 if (change_type == ProvidedFileSystemObserver::DELETED) { |
558 UnobserveEntry(observed_path, base::Bind(&EmptyStatusCallback)); | 620 // Make a copy, since the |it| iterator will get invalidated on the last |
621 // subscriber. | |
622 Subscribers subscribers = it->second.subscribers; | |
623 for (const auto& subscriber_it : subscribers) { | |
624 UnobserveEntry(subscriber_it.second.origin, | |
625 observed_path, | |
626 base::Bind(&EmptyStatusCallback)); | |
627 } | |
628 } | |
559 } | 629 } |
560 | 630 |
561 } // namespace file_system_provider | 631 } // namespace file_system_provider |
562 } // namespace chromeos | 632 } // namespace chromeos |
OLD | NEW |