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
3 // found in the LICENSE file.
5 #include "chrome/browser/chromeos/file_system_provider/provided_file_system.h"
9 #include "base/files/file.h"
10 #include "base/trace_event/trace_event.h"
11 #include "chrome/browser/chromeos/file_system_provider/notification_manager.h"
12 #include "chrome/browser/chromeos/file_system_provider/operations/abort.h"
13 #include "chrome/browser/chromeos/file_system_provider/operations/add_watcher.h"
14 #include "chrome/browser/chromeos/file_system_provider/operations/close_file.h"
15 #include "chrome/browser/chromeos/file_system_provider/operations/copy_entry.h"
16 #include "chrome/browser/chromeos/file_system_provider/operations/create_directory.h"
17 #include "chrome/browser/chromeos/file_system_provider/operations/create_file.h"
18 #include "chrome/browser/chromeos/file_system_provider/operations/delete_entry.h"
19 #include "chrome/browser/chromeos/file_system_provider/operations/get_metadata.h"
20 #include "chrome/browser/chromeos/file_system_provider/operations/move_entry.h"
21 #include "chrome/browser/chromeos/file_system_provider/operations/open_file.h"
22 #include "chrome/browser/chromeos/file_system_provider/operations/read_directory.h"
23 #include "chrome/browser/chromeos/file_system_provider/operations/read_file.h"
24 #include "chrome/browser/chromeos/file_system_provider/operations/remove_watcher.h"
25 #include "chrome/browser/chromeos/file_system_provider/operations/truncate.h"
26 #include "chrome/browser/chromeos/file_system_provider/operations/unmount.h"
27 #include "chrome/browser/chromeos/file_system_provider/operations/write_file.h"
28 #include "chrome/browser/chromeos/file_system_provider/request_manager.h"
29 #include "chrome/browser/profiles/profile.h"
30 #include "chrome/common/extensions/api/file_system_provider.h"
31 #include "extensions/browser/event_router.h"
38 namespace file_system_provider
{
41 // Discards the result of Abort() when called from the destructor.
42 void EmptyStatusCallback(base::File::Error
/* result */) {
47 AutoUpdater::AutoUpdater(const base::Closure
& update_callback
)
48 : update_callback_(update_callback
),
49 created_callbacks_(0),
50 pending_callbacks_(0) {
53 base::Closure
AutoUpdater::CreateCallback() {
56 return base::Bind(&AutoUpdater::OnPendingCallback
, this);
59 void AutoUpdater::OnPendingCallback() {
60 DCHECK_LT(0, pending_callbacks_
);
61 if (--pending_callbacks_
== 0)
62 update_callback_
.Run();
65 AutoUpdater::~AutoUpdater() {
66 // If no callbacks are created, then we need to invoke updating in the
68 if (!created_callbacks_
)
69 update_callback_
.Run();
70 else if (pending_callbacks_
)
71 LOG(ERROR
) << "Not all callbacks called. This may happen on shutdown.";
74 struct ProvidedFileSystem::AddWatcherInQueueArgs
{
75 AddWatcherInQueueArgs(size_t token
,
77 const base::FilePath
& entry_path
,
80 const storage::AsyncFileUtil::StatusCallback
& callback
,
81 const storage::WatcherManager::NotificationCallback
&
82 notification_callback
)
85 entry_path(entry_path
),
87 persistent(persistent
),
89 notification_callback(notification_callback
) {}
90 ~AddWatcherInQueueArgs() {}
94 const base::FilePath entry_path
;
96 const bool persistent
;
97 const storage::AsyncFileUtil::StatusCallback callback
;
98 const storage::WatcherManager::NotificationCallback notification_callback
;
101 struct ProvidedFileSystem::NotifyInQueueArgs
{
102 NotifyInQueueArgs(size_t token
,
103 const base::FilePath
& entry_path
,
105 storage::WatcherManager::ChangeType change_type
,
106 scoped_ptr
<ProvidedFileSystemObserver::Changes
> changes
,
107 const std::string
& tag
,
108 const storage::AsyncFileUtil::StatusCallback
& callback
)
110 entry_path(entry_path
),
111 recursive(recursive
),
112 change_type(change_type
),
113 changes(changes
.Pass()),
115 callback(callback
) {}
116 ~NotifyInQueueArgs() {}
119 const base::FilePath entry_path
;
120 const bool recursive
;
121 const storage::WatcherManager::ChangeType change_type
;
122 const scoped_ptr
<ProvidedFileSystemObserver::Changes
> changes
;
123 const std::string tag
;
124 const storage::AsyncFileUtil::StatusCallback callback
;
127 DISALLOW_COPY_AND_ASSIGN(NotifyInQueueArgs
);
130 ProvidedFileSystem::ProvidedFileSystem(
132 const ProvidedFileSystemInfo
& file_system_info
)
134 event_router_(extensions::EventRouter::Get(profile
)), // May be NULL.
135 file_system_info_(file_system_info
),
136 notification_manager_(
137 new NotificationManager(profile_
, file_system_info_
)),
138 request_manager_(new RequestManager(notification_manager_
.get())),
140 weak_ptr_factory_(this) {
143 ProvidedFileSystem::~ProvidedFileSystem() {
144 const std::vector
<int> request_ids
= request_manager_
->GetActiveRequestIds();
145 for (size_t i
= 0; i
< request_ids
.size(); ++i
) {
146 Abort(request_ids
[i
]);
150 void ProvidedFileSystem::SetEventRouterForTesting(
151 extensions::EventRouter
* event_router
) {
152 event_router_
= event_router
;
155 void ProvidedFileSystem::SetNotificationManagerForTesting(
156 scoped_ptr
<NotificationManagerInterface
> notification_manager
) {
157 notification_manager_
= notification_manager
.Pass();
158 request_manager_
.reset(new RequestManager(notification_manager_
.get()));
161 AbortCallback
ProvidedFileSystem::RequestUnmount(
162 const storage::AsyncFileUtil::StatusCallback
& callback
) {
163 const int request_id
= request_manager_
->CreateRequest(
165 scoped_ptr
<RequestManager::HandlerInterface
>(
166 new operations::Unmount(event_router_
, file_system_info_
, callback
)));
168 callback
.Run(base::File::FILE_ERROR_SECURITY
);
169 return AbortCallback();
173 &ProvidedFileSystem::Abort
, weak_ptr_factory_
.GetWeakPtr(), request_id
);
176 AbortCallback
ProvidedFileSystem::GetMetadata(
177 const base::FilePath
& entry_path
,
178 MetadataFieldMask fields
,
179 const GetMetadataCallback
& callback
) {
180 const int request_id
= request_manager_
->CreateRequest(
182 scoped_ptr
<RequestManager::HandlerInterface
>(new operations::GetMetadata(
183 event_router_
, file_system_info_
, entry_path
, fields
, callback
)));
185 callback
.Run(make_scoped_ptr
<EntryMetadata
>(NULL
),
186 base::File::FILE_ERROR_SECURITY
);
187 return AbortCallback();
191 &ProvidedFileSystem::Abort
, weak_ptr_factory_
.GetWeakPtr(), request_id
);
194 AbortCallback
ProvidedFileSystem::ReadDirectory(
195 const base::FilePath
& directory_path
,
196 const storage::AsyncFileUtil::ReadDirectoryCallback
& callback
) {
197 const int request_id
= request_manager_
->CreateRequest(
199 scoped_ptr
<RequestManager::HandlerInterface
>(
200 new operations::ReadDirectory(
201 event_router_
, file_system_info_
, directory_path
, callback
)));
203 callback
.Run(base::File::FILE_ERROR_SECURITY
,
204 storage::AsyncFileUtil::EntryList(),
205 false /* has_more */);
206 return AbortCallback();
210 &ProvidedFileSystem::Abort
, weak_ptr_factory_
.GetWeakPtr(), request_id
);
213 AbortCallback
ProvidedFileSystem::ReadFile(
215 net::IOBuffer
* buffer
,
218 const ReadChunkReceivedCallback
& callback
) {
220 "file_system_provider", "ProvidedFileSystem::ReadFile", "length", length
);
221 const int request_id
= request_manager_
->CreateRequest(
223 make_scoped_ptr
<RequestManager::HandlerInterface
>(
224 new operations::ReadFile(event_router_
,
232 callback
.Run(0 /* chunk_length */,
233 false /* has_more */,
234 base::File::FILE_ERROR_SECURITY
);
235 return AbortCallback();
239 &ProvidedFileSystem::Abort
, weak_ptr_factory_
.GetWeakPtr(), request_id
);
242 AbortCallback
ProvidedFileSystem::OpenFile(const base::FilePath
& file_path
,
244 const OpenFileCallback
& callback
) {
245 const int request_id
= request_manager_
->CreateRequest(
247 scoped_ptr
<RequestManager::HandlerInterface
>(new operations::OpenFile(
248 event_router_
, file_system_info_
, file_path
, mode
,
249 base::Bind(&ProvidedFileSystem::OnOpenFileCompleted
,
250 weak_ptr_factory_
.GetWeakPtr(), file_path
, mode
,
253 callback
.Run(0 /* file_handle */, base::File::FILE_ERROR_SECURITY
);
254 return AbortCallback();
258 &ProvidedFileSystem::Abort
, weak_ptr_factory_
.GetWeakPtr(), request_id
);
261 AbortCallback
ProvidedFileSystem::CloseFile(
263 const storage::AsyncFileUtil::StatusCallback
& callback
) {
264 const int request_id
= request_manager_
->CreateRequest(
266 scoped_ptr
<RequestManager::HandlerInterface
>(new operations::CloseFile(
267 event_router_
, file_system_info_
, file_handle
,
268 base::Bind(&ProvidedFileSystem::OnCloseFileCompleted
,
269 weak_ptr_factory_
.GetWeakPtr(), file_handle
, callback
))));
271 callback
.Run(base::File::FILE_ERROR_SECURITY
);
272 return AbortCallback();
276 &ProvidedFileSystem::Abort
, weak_ptr_factory_
.GetWeakPtr(), request_id
);
279 AbortCallback
ProvidedFileSystem::CreateDirectory(
280 const base::FilePath
& directory_path
,
282 const storage::AsyncFileUtil::StatusCallback
& callback
) {
283 const int request_id
= request_manager_
->CreateRequest(
285 scoped_ptr
<RequestManager::HandlerInterface
>(
286 new operations::CreateDirectory(event_router_
,
292 callback
.Run(base::File::FILE_ERROR_SECURITY
);
293 return AbortCallback();
297 &ProvidedFileSystem::Abort
, weak_ptr_factory_
.GetWeakPtr(), request_id
);
300 AbortCallback
ProvidedFileSystem::DeleteEntry(
301 const base::FilePath
& entry_path
,
303 const storage::AsyncFileUtil::StatusCallback
& callback
) {
304 const int request_id
= request_manager_
->CreateRequest(
306 scoped_ptr
<RequestManager::HandlerInterface
>(new operations::DeleteEntry(
307 event_router_
, file_system_info_
, entry_path
, recursive
, callback
)));
309 callback
.Run(base::File::FILE_ERROR_SECURITY
);
310 return AbortCallback();
314 &ProvidedFileSystem::Abort
, weak_ptr_factory_
.GetWeakPtr(), request_id
);
317 AbortCallback
ProvidedFileSystem::CreateFile(
318 const base::FilePath
& file_path
,
319 const storage::AsyncFileUtil::StatusCallback
& callback
) {
320 const int request_id
= request_manager_
->CreateRequest(
322 scoped_ptr
<RequestManager::HandlerInterface
>(new operations::CreateFile(
323 event_router_
, file_system_info_
, file_path
, callback
)));
325 callback
.Run(base::File::FILE_ERROR_SECURITY
);
326 return AbortCallback();
330 &ProvidedFileSystem::Abort
, weak_ptr_factory_
.GetWeakPtr(), request_id
);
333 AbortCallback
ProvidedFileSystem::CopyEntry(
334 const base::FilePath
& source_path
,
335 const base::FilePath
& target_path
,
336 const storage::AsyncFileUtil::StatusCallback
& callback
) {
337 const int request_id
= request_manager_
->CreateRequest(
339 scoped_ptr
<RequestManager::HandlerInterface
>(
340 new operations::CopyEntry(event_router_
,
346 callback
.Run(base::File::FILE_ERROR_SECURITY
);
347 return AbortCallback();
351 &ProvidedFileSystem::Abort
, weak_ptr_factory_
.GetWeakPtr(), request_id
);
354 AbortCallback
ProvidedFileSystem::WriteFile(
356 net::IOBuffer
* buffer
,
359 const storage::AsyncFileUtil::StatusCallback
& callback
) {
360 TRACE_EVENT1("file_system_provider",
361 "ProvidedFileSystem::WriteFile",
364 const int request_id
= request_manager_
->CreateRequest(
366 make_scoped_ptr
<RequestManager::HandlerInterface
>(
367 new operations::WriteFile(event_router_
,
370 make_scoped_refptr(buffer
),
375 callback
.Run(base::File::FILE_ERROR_SECURITY
);
376 return AbortCallback();
380 &ProvidedFileSystem::Abort
, weak_ptr_factory_
.GetWeakPtr(), request_id
);
383 AbortCallback
ProvidedFileSystem::MoveEntry(
384 const base::FilePath
& source_path
,
385 const base::FilePath
& target_path
,
386 const storage::AsyncFileUtil::StatusCallback
& callback
) {
387 const int request_id
= request_manager_
->CreateRequest(
389 scoped_ptr
<RequestManager::HandlerInterface
>(
390 new operations::MoveEntry(event_router_
,
396 callback
.Run(base::File::FILE_ERROR_SECURITY
);
397 return AbortCallback();
401 &ProvidedFileSystem::Abort
, weak_ptr_factory_
.GetWeakPtr(), request_id
);
404 AbortCallback
ProvidedFileSystem::Truncate(
405 const base::FilePath
& file_path
,
407 const storage::AsyncFileUtil::StatusCallback
& callback
) {
408 const int request_id
= request_manager_
->CreateRequest(
410 scoped_ptr
<RequestManager::HandlerInterface
>(new operations::Truncate(
411 event_router_
, file_system_info_
, file_path
, length
, callback
)));
413 callback
.Run(base::File::FILE_ERROR_SECURITY
);
414 return AbortCallback();
418 &ProvidedFileSystem::Abort
, weak_ptr_factory_
.GetWeakPtr(), request_id
);
421 AbortCallback
ProvidedFileSystem::AddWatcher(
423 const base::FilePath
& entry_path
,
426 const storage::AsyncFileUtil::StatusCallback
& callback
,
427 const storage::WatcherManager::NotificationCallback
&
428 notification_callback
) {
429 const size_t token
= watcher_queue_
.NewToken();
430 watcher_queue_
.Enqueue(
431 token
, base::Bind(&ProvidedFileSystem::AddWatcherInQueue
,
432 base::Unretained(this), // Outlived by the queue.
433 AddWatcherInQueueArgs(token
, origin
, entry_path
,
434 recursive
, persistent
, callback
,
435 notification_callback
)));
436 return AbortCallback();
439 void ProvidedFileSystem::RemoveWatcher(
441 const base::FilePath
& entry_path
,
443 const storage::AsyncFileUtil::StatusCallback
& callback
) {
444 const size_t token
= watcher_queue_
.NewToken();
445 watcher_queue_
.Enqueue(
446 token
, base::Bind(&ProvidedFileSystem::RemoveWatcherInQueue
,
447 base::Unretained(this), // Outlived by the queue.
448 token
, origin
, entry_path
, recursive
, callback
));
451 const ProvidedFileSystemInfo
& ProvidedFileSystem::GetFileSystemInfo() const {
452 return file_system_info_
;
455 RequestManager
* ProvidedFileSystem::GetRequestManager() {
456 return request_manager_
.get();
459 Watchers
* ProvidedFileSystem::GetWatchers() {
463 const OpenedFiles
& ProvidedFileSystem::GetOpenedFiles() const {
464 return opened_files_
;
467 void ProvidedFileSystem::AddObserver(ProvidedFileSystemObserver
* observer
) {
469 observers_
.AddObserver(observer
);
472 void ProvidedFileSystem::RemoveObserver(ProvidedFileSystemObserver
* observer
) {
474 observers_
.RemoveObserver(observer
);
477 void ProvidedFileSystem::Notify(
478 const base::FilePath
& entry_path
,
480 storage::WatcherManager::ChangeType change_type
,
481 scoped_ptr
<ProvidedFileSystemObserver::Changes
> changes
,
482 const std::string
& tag
,
483 const storage::AsyncFileUtil::StatusCallback
& callback
) {
484 const size_t token
= watcher_queue_
.NewToken();
485 watcher_queue_
.Enqueue(
486 token
, base::Bind(&ProvidedFileSystem::NotifyInQueue
,
487 base::Unretained(this), // Outlived by the queue.
488 base::Passed(make_scoped_ptr(new NotifyInQueueArgs(
489 token
, entry_path
, recursive
, change_type
,
490 changes
.Pass(), tag
, callback
)))));
493 void ProvidedFileSystem::Abort(int operation_request_id
) {
494 request_manager_
->RejectRequest(operation_request_id
,
495 make_scoped_ptr(new RequestValue()),
496 base::File::FILE_ERROR_ABORT
);
497 if (!request_manager_
->CreateRequest(
499 scoped_ptr
<RequestManager::HandlerInterface
>(new operations::Abort(
500 event_router_
, file_system_info_
, operation_request_id
,
501 base::Bind(&EmptyStatusCallback
))))) {
502 LOG(ERROR
) << "Failed to create an abort request.";
506 AbortCallback
ProvidedFileSystem::AddWatcherInQueue(
507 const AddWatcherInQueueArgs
& args
) {
508 if (args
.persistent
&& (!file_system_info_
.supports_notify_tag() ||
509 !args
.notification_callback
.is_null())) {
510 OnAddWatcherInQueueCompleted(args
.token
, args
.entry_path
, args
.recursive
,
511 Subscriber(), args
.callback
,
512 base::File::FILE_ERROR_INVALID_OPERATION
);
513 return AbortCallback();
516 // Create a candidate subscriber. This could be done in OnAddWatcherCompleted,
517 // but base::Bind supports only up to 7 arguments.
518 Subscriber subscriber
;
519 subscriber
.origin
= args
.origin
;
520 subscriber
.persistent
= args
.persistent
;
521 subscriber
.notification_callback
= args
.notification_callback
;
523 const WatcherKey
key(args
.entry_path
, args
.recursive
);
524 const Watchers::const_iterator it
= watchers_
.find(key
);
525 if (it
!= watchers_
.end()) {
526 const bool exists
= it
->second
.subscribers
.find(args
.origin
) !=
527 it
->second
.subscribers
.end();
528 OnAddWatcherInQueueCompleted(
529 args
.token
, args
.entry_path
, args
.recursive
, subscriber
, args
.callback
,
530 exists
? base::File::FILE_ERROR_EXISTS
: base::File::FILE_OK
);
531 return AbortCallback();
534 const int request_id
= request_manager_
->CreateRequest(
536 scoped_ptr
<RequestManager::HandlerInterface
>(new operations::AddWatcher(
537 event_router_
, file_system_info_
, args
.entry_path
, args
.recursive
,
538 base::Bind(&ProvidedFileSystem::OnAddWatcherInQueueCompleted
,
539 weak_ptr_factory_
.GetWeakPtr(), args
.token
,
540 args
.entry_path
, args
.recursive
, subscriber
,
544 OnAddWatcherInQueueCompleted(args
.token
, args
.entry_path
, args
.recursive
,
545 subscriber
, args
.callback
,
546 base::File::FILE_ERROR_SECURITY
);
549 return AbortCallback();
552 AbortCallback
ProvidedFileSystem::RemoveWatcherInQueue(
555 const base::FilePath
& entry_path
,
557 const storage::AsyncFileUtil::StatusCallback
& callback
) {
558 const WatcherKey
key(entry_path
, recursive
);
559 const Watchers::iterator it
= watchers_
.find(key
);
560 if (it
== watchers_
.end() ||
561 it
->second
.subscribers
.find(origin
) == it
->second
.subscribers
.end()) {
562 OnRemoveWatcherInQueueCompleted(token
, origin
, key
, callback
,
563 false /* extension_response */,
564 base::File::FILE_ERROR_NOT_FOUND
);
565 return AbortCallback();
568 // If there are other subscribers, then do not remove the observer, but simply
570 if (it
->second
.subscribers
.size() > 1) {
571 OnRemoveWatcherInQueueCompleted(token
, origin
, key
, callback
,
572 false /* extension_response */,
573 base::File::FILE_OK
);
574 return AbortCallback();
577 // Otherwise, emit an event, and remove the watcher.
578 request_manager_
->CreateRequest(
580 scoped_ptr
<RequestManager::HandlerInterface
>(
581 new operations::RemoveWatcher(
582 event_router_
, file_system_info_
, entry_path
, recursive
,
583 base::Bind(&ProvidedFileSystem::OnRemoveWatcherInQueueCompleted
,
584 weak_ptr_factory_
.GetWeakPtr(), token
, origin
, key
,
585 callback
, true /* extension_response */))));
587 return AbortCallback();
590 AbortCallback
ProvidedFileSystem::NotifyInQueue(
591 scoped_ptr
<NotifyInQueueArgs
> args
) {
592 const WatcherKey
key(args
->entry_path
, args
->recursive
);
593 const auto& watcher_it
= watchers_
.find(key
);
594 if (watcher_it
== watchers_
.end()) {
595 OnNotifyInQueueCompleted(args
.Pass(), base::File::FILE_ERROR_NOT_FOUND
);
596 return AbortCallback();
599 // The tag must be provided if and only if it's explicitly supported.
600 if (file_system_info_
.supports_notify_tag() == args
->tag
.empty()) {
601 OnNotifyInQueueCompleted(args
.Pass(),
602 base::File::FILE_ERROR_INVALID_OPERATION
);
603 return AbortCallback();
606 // It's illegal to provide a tag which is not unique.
607 if (!args
->tag
.empty() && args
->tag
== watcher_it
->second
.last_tag
) {
608 OnNotifyInQueueCompleted(args
.Pass(),
609 base::File::FILE_ERROR_INVALID_OPERATION
);
610 return AbortCallback();
613 // The object is owned by AutoUpdated, so the reference is valid as long as
614 // callbacks created with AutoUpdater::CreateCallback().
615 const ProvidedFileSystemObserver::Changes
& changes_ref
= *args
->changes
.get();
616 const storage::WatcherManager::ChangeType change_type
= args
->change_type
;
618 scoped_refptr
<AutoUpdater
> auto_updater(
619 new AutoUpdater(base::Bind(&ProvidedFileSystem::OnNotifyInQueueCompleted
,
620 weak_ptr_factory_
.GetWeakPtr(),
621 base::Passed(&args
), base::File::FILE_OK
)));
623 // Call all notification callbacks (if any).
624 for (const auto& subscriber_it
: watcher_it
->second
.subscribers
) {
625 const storage::WatcherManager::NotificationCallback
& notification_callback
=
626 subscriber_it
.second
.notification_callback
;
627 if (!notification_callback
.is_null())
628 notification_callback
.Run(change_type
);
631 // Notify all observers.
632 FOR_EACH_OBSERVER(ProvidedFileSystemObserver
,
634 OnWatcherChanged(file_system_info_
,
638 auto_updater
->CreateCallback()));
640 return AbortCallback();
643 base::WeakPtr
<ProvidedFileSystemInterface
> ProvidedFileSystem::GetWeakPtr() {
644 return weak_ptr_factory_
.GetWeakPtr();
647 void ProvidedFileSystem::OnAddWatcherInQueueCompleted(
649 const base::FilePath
& entry_path
,
651 const Subscriber
& subscriber
,
652 const storage::AsyncFileUtil::StatusCallback
& callback
,
653 base::File::Error result
) {
654 if (result
!= base::File::FILE_OK
) {
655 callback
.Run(result
);
656 watcher_queue_
.Complete(token
);
660 const WatcherKey
key(entry_path
, recursive
);
661 const Watchers::iterator it
= watchers_
.find(key
);
662 if (it
!= watchers_
.end()) {
663 callback
.Run(base::File::FILE_OK
);
664 watcher_queue_
.Complete(token
);
668 Watcher
* const watcher
= &watchers_
[key
];
669 watcher
->entry_path
= entry_path
;
670 watcher
->recursive
= recursive
;
671 watcher
->subscribers
[subscriber
.origin
] = subscriber
;
673 FOR_EACH_OBSERVER(ProvidedFileSystemObserver
,
675 OnWatcherListChanged(file_system_info_
, watchers_
));
677 callback
.Run(base::File::FILE_OK
);
678 watcher_queue_
.Complete(token
);
681 void ProvidedFileSystem::OnRemoveWatcherInQueueCompleted(
684 const WatcherKey
& key
,
685 const storage::AsyncFileUtil::StatusCallback
& callback
,
686 bool extension_response
,
687 base::File::Error result
) {
688 if (!extension_response
&& result
!= base::File::FILE_OK
) {
689 watcher_queue_
.Complete(token
);
690 callback
.Run(result
);
694 // Even if the extension returns an error, the callback is called with base::
696 const auto it
= watchers_
.find(key
);
697 DCHECK(it
!= watchers_
.end());
698 DCHECK(it
->second
.subscribers
.find(origin
) != it
->second
.subscribers
.end());
700 it
->second
.subscribers
.erase(origin
);
702 FOR_EACH_OBSERVER(ProvidedFileSystemObserver
, observers_
,
703 OnWatcherListChanged(file_system_info_
, watchers_
));
705 // If there are no more subscribers, then remove the watcher.
706 if (!it
->second
.subscribers
.size())
709 callback
.Run(base::File::FILE_OK
);
710 watcher_queue_
.Complete(token
);
713 void ProvidedFileSystem::OnNotifyInQueueCompleted(
714 scoped_ptr
<NotifyInQueueArgs
> args
,
715 base::File::Error result
) {
716 if (result
!= base::File::FILE_OK
) {
717 args
->callback
.Run(result
);
718 watcher_queue_
.Complete(args
->token
);
722 // Check if the entry is still watched.
723 const WatcherKey
key(args
->entry_path
, args
->recursive
);
724 const Watchers::iterator it
= watchers_
.find(key
);
725 if (it
== watchers_
.end()) {
726 args
->callback
.Run(base::File::FILE_ERROR_NOT_FOUND
);
727 watcher_queue_
.Complete(args
->token
);
731 it
->second
.last_tag
= args
->tag
;
733 FOR_EACH_OBSERVER(ProvidedFileSystemObserver
,
735 OnWatcherTagUpdated(file_system_info_
, it
->second
));
737 // If the watched entry is deleted, then remove the watcher.
738 if (args
->change_type
== storage::WatcherManager::DELETED
) {
739 // Make a copy, since the |it| iterator will get invalidated on the last
741 Subscribers subscribers
= it
->second
.subscribers
;
742 for (const auto& subscriber_it
: subscribers
) {
743 RemoveWatcher(subscriber_it
.second
.origin
, args
->entry_path
,
744 args
->recursive
, base::Bind(&EmptyStatusCallback
));
748 args
->callback
.Run(base::File::FILE_OK
);
749 watcher_queue_
.Complete(args
->token
);
752 void ProvidedFileSystem::OnOpenFileCompleted(const base::FilePath
& file_path
,
754 const OpenFileCallback
& callback
,
756 base::File::Error result
) {
757 if (result
!= base::File::FILE_OK
) {
758 callback
.Run(file_handle
, result
);
762 opened_files_
[file_handle
] = OpenedFile(file_path
, mode
);
763 callback
.Run(file_handle
, base::File::FILE_OK
);
766 void ProvidedFileSystem::OnCloseFileCompleted(
768 const storage::AsyncFileUtil::StatusCallback
& callback
,
769 base::File::Error result
) {
770 // Closing files is final. Even if an error happened, we remove it from the
771 // list of opened files.
772 opened_files_
.erase(file_handle
);
773 callback
.Run(result
);
776 } // namespace file_system_provider
777 } // namespace chromeos