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 06dd39af0ab780db0b3a58112c4ce30a1f0045cc..853da613b931504afa5fc878bc11712017aed93f 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,42 @@ 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. |
| - const ObservedEntries::const_iterator it = |
| - observed_entries_.find(directory_path); |
| + |
| + if (persistent && !file_system_info_.supports_notify_tag()) { |
| + OnObserveDirectoryCompleted(origin, |
| + directory_path, |
| + recursive, |
| + persistent, |
| + callback, |
| + base::File::FILE_ERROR_INVALID_OPERATION); |
| + return AbortCallback(); |
| + } |
| + |
| + const ObservedEntries::iterator it = observed_entries_.find(directory_path); |
| if (it != observed_entries_.end()) { |
| + if (it->second.subscribers.find(origin) != it->second.subscribers.end()) { |
| + OnObserveDirectoryCompleted(origin, |
| + directory_path, |
| + recursive, |
| + persistent, |
| + callback, |
| + base::File::FILE_ERROR_EXISTS); |
| + return AbortCallback(); |
| + } |
| 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
|
| - callback.Run(base::File::FILE_ERROR_EXISTS); |
| + OnObserveDirectoryCompleted(origin, |
| + directory_path, |
| + recursive, |
| + persistent, |
| + callback, |
| + base::File::FILE_OK); |
| return AbortCallback(); |
| } |
| } |
| @@ -382,11 +415,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(); |
| } |
| @@ -395,33 +436,49 @@ ProvidedFileSystem::AbortCallback ProvidedFileSystem::ObserveDirectory( |
| } |
| void ProvidedFileSystem::UnobserveEntry( |
| + const GURL& origin, |
| const base::FilePath& entry_path, |
| const storage::AsyncFileUtil::StatusCallback& callback) { |
| - const ObservedEntries::const_iterator it = observed_entries_.find(entry_path); |
| - if (it == observed_entries_.end()) { |
| + const ObservedEntries::iterator it = observed_entries_.find(entry_path); |
| + 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, callback))); |
| + event_router_, |
| + file_system_info_, |
| + entry_path, |
| + 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 { |
| @@ -506,8 +563,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) { |
| @@ -515,8 +574,11 @@ void ProvidedFileSystem::OnObserveDirectoryCompleted( |
| return; |
| } |
| - observed_entries_[directory_path].entry_path = directory_path; |
| - observed_entries_[directory_path].recursive |= recursive; |
| + ObservedEntry* const observed_entry = &observed_entries_[directory_path]; |
| + 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, |
| @@ -554,8 +616,16 @@ 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, 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, |
| + base::Bind(&EmptyStatusCallback)); |
| + } |
| + } |
| } |
| } // namespace file_system_provider |