Chromium Code Reviews| 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..f106376bfbb1d5d95505fc9d1cb0297c535e7a41 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,19 +365,47 @@ 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()) { |
| - OnObserveDirectoryCompleted( |
| - directory_path, recursive, callback, base::File::FILE_ERROR_EXISTS); |
| + OnObserveDirectoryCompleted(origin, |
| + directory_path, |
| + recursive, |
| + persistent, |
| + callback, |
| + base::File::FILE_ERROR_EXISTS); |
| return AbortCallback(); |
| } |
| + if (it != observed_entries_.end()) { |
|
hirono
2014/10/27 04:50:31
it != observed_entries_.end() is always false beca
mtomasz
2014/10/27 05:01:18
Right. Done.
|
| + if (it->second.subscribers.find(origin) != it->second.subscribers.end()) { |
| + OnObserveDirectoryCompleted(origin, |
| + directory_path, |
| + recursive, |
| + persistent, |
| + callback, |
| + base::File::FILE_ERROR_EXISTS); |
| + return AbortCallback(); |
| + } |
| + } |
| + |
| const int request_id = request_manager_->CreateRequest( |
| OBSERVE_DIRECTORY, |
| scoped_ptr<RequestManager::HandlerInterface>( |
| @@ -381,11 +416,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 +437,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 +568,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 +586,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 +630,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 |