| Index: chrome/browser/chromeos/file_system_provider/provided_file_system.cc
|
| diff --git a/chrome/browser/chromeos/file_system_provider/provided_file_system.cc b/chrome/browser/chromeos/file_system_provider/provided_file_system.cc
|
| index cdf9c0382ea336e44896da5be8e6f3810f0c0182..4abc1bf0da27748ca6f4fc75c7c3b9dd3fad876e 100644
|
| --- a/chrome/browser/chromeos/file_system_provider/provided_file_system.cc
|
| +++ b/chrome/browser/chromeos/file_system_provider/provided_file_system.cc
|
| @@ -42,6 +42,13 @@ namespace {
|
| void EmptyStatusCallback(base::File::Error /* result */) {
|
| }
|
|
|
| +// Discards the error code and always calls the callback with a success.
|
| +void AlwaysSuccessCallback(
|
| + const storage::AsyncFileUtil::StatusCallback& callback,
|
| + base::File::Error /* result */) {
|
| + callback.Run(base::File::FILE_OK);
|
| +}
|
| +
|
| } // namespace
|
|
|
| AutoUpdater::AutoUpdater(const base::Closure& update_callback)
|
| @@ -358,16 +365,35 @@ ProvidedFileSystem::AbortCallback ProvidedFileSystem::Truncate(
|
| }
|
|
|
| ProvidedFileSystem::AbortCallback ProvidedFileSystem::ObserveDirectory(
|
| + const GURL& origin,
|
| const base::FilePath& directory_path,
|
| bool recursive,
|
| + bool persistent,
|
| const storage::AsyncFileUtil::StatusCallback& callback) {
|
| // TODO(mtomasz): Wrap the entire method body with an asynchronous queue to
|
| // avoid races.
|
| + if (persistent && !file_system_info_.supports_notify_tag()) {
|
| + OnObserveDirectoryCompleted(origin,
|
| + directory_path,
|
| + recursive,
|
| + persistent,
|
| + callback,
|
| + base::File::FILE_ERROR_INVALID_OPERATION);
|
| + return AbortCallback();
|
| + }
|
| +
|
| const ObservedEntryKey key(directory_path, recursive);
|
| const ObservedEntries::const_iterator it = observed_entries_.find(key);
|
| if (it != observed_entries_.end()) {
|
| + const bool exists =
|
| + it->second.subscribers.find(origin) != it->second.subscribers.end();
|
| OnObserveDirectoryCompleted(
|
| - directory_path, recursive, callback, base::File::FILE_ERROR_EXISTS);
|
| + origin,
|
| + directory_path,
|
| + recursive,
|
| + persistent,
|
| + callback,
|
| + exists ? base::File::FILE_ERROR_EXISTS : base::File::FILE_OK);
|
| return AbortCallback();
|
| }
|
|
|
| @@ -381,11 +407,19 @@ ProvidedFileSystem::AbortCallback ProvidedFileSystem::ObserveDirectory(
|
| recursive,
|
| base::Bind(&ProvidedFileSystem::OnObserveDirectoryCompleted,
|
| weak_ptr_factory_.GetWeakPtr(),
|
| + origin,
|
| directory_path,
|
| recursive,
|
| + persistent,
|
| callback))));
|
| +
|
| if (!request_id) {
|
| - callback.Run(base::File::FILE_ERROR_SECURITY);
|
| + OnObserveDirectoryCompleted(origin,
|
| + directory_path,
|
| + recursive,
|
| + persistent,
|
| + callback,
|
| + base::File::FILE_ERROR_SECURITY);
|
| return AbortCallback();
|
| }
|
|
|
| @@ -394,38 +428,51 @@ ProvidedFileSystem::AbortCallback ProvidedFileSystem::ObserveDirectory(
|
| }
|
|
|
| void ProvidedFileSystem::UnobserveEntry(
|
| + const GURL& origin,
|
| const base::FilePath& entry_path,
|
| bool recursive,
|
| const storage::AsyncFileUtil::StatusCallback& callback) {
|
| const ObservedEntryKey key(entry_path, recursive);
|
| - const ObservedEntries::const_iterator it = observed_entries_.find(key);
|
| - if (it == observed_entries_.end()) {
|
| + const ObservedEntries::iterator it = observed_entries_.find(key);
|
| + if (it == observed_entries_.end() ||
|
| + it->second.subscribers.find(origin) == it->second.subscribers.end()) {
|
| callback.Run(base::File::FILE_ERROR_NOT_FOUND);
|
| return;
|
| }
|
|
|
| - // Delete the watcher in advance since the list of observed entries is owned
|
| - // by the C++ layer, not by the extension.
|
| - observed_entries_.erase(it);
|
| + // Delete the subscriber in advance, since the list of observed entries is
|
| + // owned by the C++ layer, not by the extension.
|
| + it->second.subscribers.erase(origin);
|
|
|
| FOR_EACH_OBSERVER(
|
| ProvidedFileSystemObserver,
|
| observers_,
|
| OnObservedEntryListChanged(file_system_info_, observed_entries_));
|
|
|
| - // TODO(mtomasz): Consider returning always an OK error code, since for the
|
| - // callers it's important that the entry is not watched anymore. The watcher
|
| - // is removed even if the extension returns an error.
|
| + // If there are other subscribers, then do not remove the obsererver, but
|
| + // simply return a success.
|
| + if (it->second.subscribers.size()) {
|
| + callback.Run(base::File::FILE_OK);
|
| + return;
|
| + }
|
| +
|
| + // Delete the watcher in advance.
|
| + observed_entries_.erase(it);
|
| +
|
| + // Even if the extension returns an error, the callback is called with base::
|
| + // File::FILE_OK. The reason for that is that the observed is not watched
|
| + // anymore anyway, as it's removed in advance.
|
| const int request_id = request_manager_->CreateRequest(
|
| UNOBSERVE_ENTRY,
|
| scoped_ptr<RequestManager::HandlerInterface>(
|
| - new operations::UnobserveEntry(event_router_,
|
| - file_system_info_,
|
| - entry_path,
|
| - recursive,
|
| - callback)));
|
| + new operations::UnobserveEntry(
|
| + event_router_,
|
| + file_system_info_,
|
| + entry_path,
|
| + recursive,
|
| + base::Bind(&AlwaysSuccessCallback, callback))));
|
| if (!request_id)
|
| - callback.Run(base::File::FILE_ERROR_SECURITY);
|
| + callback.Run(base::File::FILE_OK);
|
| }
|
|
|
| const ProvidedFileSystemInfo& ProvidedFileSystem::GetFileSystemInfo() const {
|
| @@ -512,8 +559,10 @@ void ProvidedFileSystem::Abort(
|
| }
|
|
|
| void ProvidedFileSystem::OnObserveDirectoryCompleted(
|
| + const GURL& origin,
|
| const base::FilePath& directory_path,
|
| bool recursive,
|
| + bool persistent,
|
| const storage::AsyncFileUtil::StatusCallback& callback,
|
| base::File::Error result) {
|
| if (result != base::File::FILE_OK) {
|
| @@ -528,8 +577,11 @@ void ProvidedFileSystem::OnObserveDirectoryCompleted(
|
| return;
|
| }
|
|
|
| - observed_entries_[key].entry_path = directory_path;
|
| - observed_entries_[key].recursive = recursive;
|
| + ObservedEntry* const observed_entry = &observed_entries_[key];
|
| + observed_entry->entry_path = directory_path;
|
| + observed_entry->recursive = recursive;
|
| + observed_entry->subscribers[origin].origin = origin;
|
| + observed_entry->subscribers[origin].persistent |= persistent;
|
|
|
| FOR_EACH_OBSERVER(
|
| ProvidedFileSystemObserver,
|
| @@ -569,8 +621,17 @@ void ProvidedFileSystem::OnNotifyCompleted(
|
| OnObservedEntryTagUpdated(file_system_info_, it->second));
|
|
|
| // If the observed entry is deleted, then unobserve it.
|
| - if (change_type == ProvidedFileSystemObserver::DELETED)
|
| - UnobserveEntry(observed_path, recursive, base::Bind(&EmptyStatusCallback));
|
| + if (change_type == ProvidedFileSystemObserver::DELETED) {
|
| + // Make a copy, since the |it| iterator will get invalidated on the last
|
| + // subscriber.
|
| + Subscribers subscribers = it->second.subscribers;
|
| + for (const auto& subscriber_it : subscribers) {
|
| + UnobserveEntry(subscriber_it.second.origin,
|
| + observed_path,
|
| + recursive,
|
| + base::Bind(&EmptyStatusCallback));
|
| + }
|
| + }
|
| }
|
|
|
| } // namespace file_system_provider
|
|
|