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/configure.h"
16 #include "chrome/browser/chromeos/file_system_provider/operations/copy_entry.h"
17 #include "chrome/browser/chromeos/file_system_provider/operations/create_directory.h"
18 #include "chrome/browser/chromeos/file_system_provider/operations/create_file.h"
19 #include "chrome/browser/chromeos/file_system_provider/operations/delete_entry.h"
20 #include "chrome/browser/chromeos/file_system_provider/operations/execute_action.h"
21 #include "chrome/browser/chromeos/file_system_provider/operations/get_actions.h"
22 #include "chrome/browser/chromeos/file_system_provider/operations/get_metadata.h"
23 #include "chrome/browser/chromeos/file_system_provider/operations/move_entry.h"
24 #include "chrome/browser/chromeos/file_system_provider/operations/open_file.h"
25 #include "chrome/browser/chromeos/file_system_provider/operations/read_directory.h"
26 #include "chrome/browser/chromeos/file_system_provider/operations/read_file.h"
27 #include "chrome/browser/chromeos/file_system_provider/operations/remove_watcher.h"
28 #include "chrome/browser/chromeos/file_system_provider/operations/truncate.h"
29 #include "chrome/browser/chromeos/file_system_provider/operations/unmount.h"
30 #include "chrome/browser/chromeos/file_system_provider/operations/write_file.h"
31 #include "chrome/browser/chromeos/file_system_provider/request_manager.h"
32 #include "chrome/browser/profiles/profile.h"
33 #include "chrome/common/extensions/api/file_system_provider.h"
34 #include "extensions/browser/event_router.h"
41 namespace file_system_provider
{
44 // Discards the result of Abort() when called from the destructor.
45 void EmptyStatusCallback(base::File::Error
/* result */) {
50 AutoUpdater::AutoUpdater(const base::Closure
& update_callback
)
51 : update_callback_(update_callback
),
52 created_callbacks_(0),
53 pending_callbacks_(0) {
56 base::Closure
AutoUpdater::CreateCallback() {
59 return base::Bind(&AutoUpdater::OnPendingCallback
, this);
62 void AutoUpdater::OnPendingCallback() {
63 DCHECK_LT(0, pending_callbacks_
);
64 if (--pending_callbacks_
== 0)
65 update_callback_
.Run();
68 AutoUpdater::~AutoUpdater() {
69 // If no callbacks are created, then we need to invoke updating in the
71 if (!created_callbacks_
)
72 update_callback_
.Run();
73 else if (pending_callbacks_
)
74 LOG(ERROR
) << "Not all callbacks called. This may happen on shutdown.";
77 struct ProvidedFileSystem::AddWatcherInQueueArgs
{
78 AddWatcherInQueueArgs(size_t token
,
80 const base::FilePath
& entry_path
,
83 const storage::AsyncFileUtil::StatusCallback
& callback
,
84 const storage::WatcherManager::NotificationCallback
&
85 notification_callback
)
88 entry_path(entry_path
),
90 persistent(persistent
),
92 notification_callback(notification_callback
) {}
93 ~AddWatcherInQueueArgs() {}
97 const base::FilePath entry_path
;
99 const bool persistent
;
100 const storage::AsyncFileUtil::StatusCallback callback
;
101 const storage::WatcherManager::NotificationCallback notification_callback
;
104 struct ProvidedFileSystem::NotifyInQueueArgs
{
105 NotifyInQueueArgs(size_t token
,
106 const base::FilePath
& entry_path
,
108 storage::WatcherManager::ChangeType change_type
,
109 scoped_ptr
<ProvidedFileSystemObserver::Changes
> changes
,
110 const std::string
& tag
,
111 const storage::AsyncFileUtil::StatusCallback
& callback
)
113 entry_path(entry_path
),
114 recursive(recursive
),
115 change_type(change_type
),
116 changes(changes
.Pass()),
118 callback(callback
) {}
119 ~NotifyInQueueArgs() {}
122 const base::FilePath entry_path
;
123 const bool recursive
;
124 const storage::WatcherManager::ChangeType change_type
;
125 const scoped_ptr
<ProvidedFileSystemObserver::Changes
> changes
;
126 const std::string tag
;
127 const storage::AsyncFileUtil::StatusCallback callback
;
130 DISALLOW_COPY_AND_ASSIGN(NotifyInQueueArgs
);
133 ProvidedFileSystem::ProvidedFileSystem(
135 const ProvidedFileSystemInfo
& file_system_info
)
137 event_router_(extensions::EventRouter::Get(profile
)), // May be NULL.
138 file_system_info_(file_system_info
),
139 notification_manager_(
140 new NotificationManager(profile_
, file_system_info_
)),
141 request_manager_(new RequestManager(profile
,
142 file_system_info
.extension_id(),
143 notification_manager_
.get())),
145 weak_ptr_factory_(this) {
148 ProvidedFileSystem::~ProvidedFileSystem() {
149 const std::vector
<int> request_ids
= request_manager_
->GetActiveRequestIds();
150 for (size_t i
= 0; i
< request_ids
.size(); ++i
) {
151 Abort(request_ids
[i
]);
155 void ProvidedFileSystem::SetEventRouterForTesting(
156 extensions::EventRouter
* event_router
) {
157 event_router_
= event_router
;
160 void ProvidedFileSystem::SetNotificationManagerForTesting(
161 scoped_ptr
<NotificationManagerInterface
> notification_manager
) {
162 notification_manager_
= notification_manager
.Pass();
163 request_manager_
.reset(new RequestManager(
164 profile_
, file_system_info_
.extension_id(), notification_manager_
.get()));
167 AbortCallback
ProvidedFileSystem::RequestUnmount(
168 const storage::AsyncFileUtil::StatusCallback
& callback
) {
169 const int request_id
= request_manager_
->CreateRequest(
171 scoped_ptr
<RequestManager::HandlerInterface
>(
172 new operations::Unmount(event_router_
, file_system_info_
, callback
)));
174 callback
.Run(base::File::FILE_ERROR_SECURITY
);
175 return AbortCallback();
179 &ProvidedFileSystem::Abort
, weak_ptr_factory_
.GetWeakPtr(), request_id
);
182 AbortCallback
ProvidedFileSystem::GetMetadata(
183 const base::FilePath
& entry_path
,
184 MetadataFieldMask fields
,
185 const GetMetadataCallback
& callback
) {
186 const int request_id
= request_manager_
->CreateRequest(
188 scoped_ptr
<RequestManager::HandlerInterface
>(new operations::GetMetadata(
189 event_router_
, file_system_info_
, entry_path
, fields
, callback
)));
191 callback
.Run(make_scoped_ptr
<EntryMetadata
>(NULL
),
192 base::File::FILE_ERROR_SECURITY
);
193 return AbortCallback();
197 &ProvidedFileSystem::Abort
, weak_ptr_factory_
.GetWeakPtr(), request_id
);
200 AbortCallback
ProvidedFileSystem::GetActions(
201 const base::FilePath
& entry_path
,
202 const GetActionsCallback
& callback
) {
203 const int request_id
= request_manager_
->CreateRequest(
205 scoped_ptr
<RequestManager::HandlerInterface
>(new operations::GetActions(
206 event_router_
, file_system_info_
, entry_path
, callback
)));
208 callback
.Run(Actions(), base::File::FILE_ERROR_SECURITY
);
209 return AbortCallback();
212 return base::Bind(&ProvidedFileSystem::Abort
, weak_ptr_factory_
.GetWeakPtr(),
216 AbortCallback
ProvidedFileSystem::ExecuteAction(
217 const base::FilePath
& entry_path
,
218 const std::string
& action_id
,
219 const storage::AsyncFileUtil::StatusCallback
& callback
) {
220 const int request_id
= request_manager_
->CreateRequest(
222 scoped_ptr
<RequestManager::HandlerInterface
>(
223 new operations::ExecuteAction(event_router_
, file_system_info_
,
224 entry_path
, action_id
, callback
)));
226 callback
.Run(base::File::FILE_ERROR_SECURITY
);
227 return AbortCallback();
230 return base::Bind(&ProvidedFileSystem::Abort
, weak_ptr_factory_
.GetWeakPtr(),
234 AbortCallback
ProvidedFileSystem::ReadDirectory(
235 const base::FilePath
& directory_path
,
236 const storage::AsyncFileUtil::ReadDirectoryCallback
& callback
) {
237 const int request_id
= request_manager_
->CreateRequest(
239 scoped_ptr
<RequestManager::HandlerInterface
>(
240 new operations::ReadDirectory(
241 event_router_
, file_system_info_
, directory_path
, callback
)));
243 callback
.Run(base::File::FILE_ERROR_SECURITY
,
244 storage::AsyncFileUtil::EntryList(),
245 false /* has_more */);
246 return AbortCallback();
250 &ProvidedFileSystem::Abort
, weak_ptr_factory_
.GetWeakPtr(), request_id
);
253 AbortCallback
ProvidedFileSystem::ReadFile(
255 net::IOBuffer
* buffer
,
258 const ReadChunkReceivedCallback
& callback
) {
260 "file_system_provider", "ProvidedFileSystem::ReadFile", "length", length
);
261 const int request_id
= request_manager_
->CreateRequest(
263 make_scoped_ptr
<RequestManager::HandlerInterface
>(
264 new operations::ReadFile(event_router_
,
272 callback
.Run(0 /* chunk_length */,
273 false /* has_more */,
274 base::File::FILE_ERROR_SECURITY
);
275 return AbortCallback();
279 &ProvidedFileSystem::Abort
, weak_ptr_factory_
.GetWeakPtr(), request_id
);
282 AbortCallback
ProvidedFileSystem::OpenFile(const base::FilePath
& file_path
,
284 const OpenFileCallback
& callback
) {
285 const int request_id
= request_manager_
->CreateRequest(
287 scoped_ptr
<RequestManager::HandlerInterface
>(new operations::OpenFile(
288 event_router_
, file_system_info_
, file_path
, mode
,
289 base::Bind(&ProvidedFileSystem::OnOpenFileCompleted
,
290 weak_ptr_factory_
.GetWeakPtr(), file_path
, mode
,
293 callback
.Run(0 /* file_handle */, base::File::FILE_ERROR_SECURITY
);
294 return AbortCallback();
298 &ProvidedFileSystem::Abort
, weak_ptr_factory_
.GetWeakPtr(), request_id
);
301 AbortCallback
ProvidedFileSystem::CloseFile(
303 const storage::AsyncFileUtil::StatusCallback
& callback
) {
304 const int request_id
= request_manager_
->CreateRequest(
306 scoped_ptr
<RequestManager::HandlerInterface
>(new operations::CloseFile(
307 event_router_
, file_system_info_
, file_handle
,
308 base::Bind(&ProvidedFileSystem::OnCloseFileCompleted
,
309 weak_ptr_factory_
.GetWeakPtr(), file_handle
, callback
))));
311 callback
.Run(base::File::FILE_ERROR_SECURITY
);
312 return AbortCallback();
316 &ProvidedFileSystem::Abort
, weak_ptr_factory_
.GetWeakPtr(), request_id
);
319 AbortCallback
ProvidedFileSystem::CreateDirectory(
320 const base::FilePath
& directory_path
,
322 const storage::AsyncFileUtil::StatusCallback
& callback
) {
323 const int request_id
= request_manager_
->CreateRequest(
325 scoped_ptr
<RequestManager::HandlerInterface
>(
326 new operations::CreateDirectory(event_router_
,
332 callback
.Run(base::File::FILE_ERROR_SECURITY
);
333 return AbortCallback();
337 &ProvidedFileSystem::Abort
, weak_ptr_factory_
.GetWeakPtr(), request_id
);
340 AbortCallback
ProvidedFileSystem::DeleteEntry(
341 const base::FilePath
& entry_path
,
343 const storage::AsyncFileUtil::StatusCallback
& callback
) {
344 const int request_id
= request_manager_
->CreateRequest(
346 scoped_ptr
<RequestManager::HandlerInterface
>(new operations::DeleteEntry(
347 event_router_
, file_system_info_
, entry_path
, recursive
, callback
)));
349 callback
.Run(base::File::FILE_ERROR_SECURITY
);
350 return AbortCallback();
354 &ProvidedFileSystem::Abort
, weak_ptr_factory_
.GetWeakPtr(), request_id
);
357 AbortCallback
ProvidedFileSystem::CreateFile(
358 const base::FilePath
& file_path
,
359 const storage::AsyncFileUtil::StatusCallback
& callback
) {
360 const int request_id
= request_manager_
->CreateRequest(
362 scoped_ptr
<RequestManager::HandlerInterface
>(new operations::CreateFile(
363 event_router_
, file_system_info_
, file_path
, callback
)));
365 callback
.Run(base::File::FILE_ERROR_SECURITY
);
366 return AbortCallback();
370 &ProvidedFileSystem::Abort
, weak_ptr_factory_
.GetWeakPtr(), request_id
);
373 AbortCallback
ProvidedFileSystem::CopyEntry(
374 const base::FilePath
& source_path
,
375 const base::FilePath
& target_path
,
376 const storage::AsyncFileUtil::StatusCallback
& callback
) {
377 const int request_id
= request_manager_
->CreateRequest(
379 scoped_ptr
<RequestManager::HandlerInterface
>(
380 new operations::CopyEntry(event_router_
,
386 callback
.Run(base::File::FILE_ERROR_SECURITY
);
387 return AbortCallback();
391 &ProvidedFileSystem::Abort
, weak_ptr_factory_
.GetWeakPtr(), request_id
);
394 AbortCallback
ProvidedFileSystem::WriteFile(
396 net::IOBuffer
* buffer
,
399 const storage::AsyncFileUtil::StatusCallback
& callback
) {
400 TRACE_EVENT1("file_system_provider",
401 "ProvidedFileSystem::WriteFile",
404 const int request_id
= request_manager_
->CreateRequest(
406 make_scoped_ptr
<RequestManager::HandlerInterface
>(
407 new operations::WriteFile(event_router_
,
410 make_scoped_refptr(buffer
),
415 callback
.Run(base::File::FILE_ERROR_SECURITY
);
416 return AbortCallback();
420 &ProvidedFileSystem::Abort
, weak_ptr_factory_
.GetWeakPtr(), request_id
);
423 AbortCallback
ProvidedFileSystem::MoveEntry(
424 const base::FilePath
& source_path
,
425 const base::FilePath
& target_path
,
426 const storage::AsyncFileUtil::StatusCallback
& callback
) {
427 const int request_id
= request_manager_
->CreateRequest(
429 scoped_ptr
<RequestManager::HandlerInterface
>(
430 new operations::MoveEntry(event_router_
,
436 callback
.Run(base::File::FILE_ERROR_SECURITY
);
437 return AbortCallback();
441 &ProvidedFileSystem::Abort
, weak_ptr_factory_
.GetWeakPtr(), request_id
);
444 AbortCallback
ProvidedFileSystem::Truncate(
445 const base::FilePath
& file_path
,
447 const storage::AsyncFileUtil::StatusCallback
& callback
) {
448 const int request_id
= request_manager_
->CreateRequest(
450 scoped_ptr
<RequestManager::HandlerInterface
>(new operations::Truncate(
451 event_router_
, file_system_info_
, file_path
, length
, callback
)));
453 callback
.Run(base::File::FILE_ERROR_SECURITY
);
454 return AbortCallback();
458 &ProvidedFileSystem::Abort
, weak_ptr_factory_
.GetWeakPtr(), request_id
);
461 AbortCallback
ProvidedFileSystem::AddWatcher(
463 const base::FilePath
& entry_path
,
466 const storage::AsyncFileUtil::StatusCallback
& callback
,
467 const storage::WatcherManager::NotificationCallback
&
468 notification_callback
) {
469 const size_t token
= watcher_queue_
.NewToken();
470 watcher_queue_
.Enqueue(
471 token
, base::Bind(&ProvidedFileSystem::AddWatcherInQueue
,
472 base::Unretained(this), // Outlived by the queue.
473 AddWatcherInQueueArgs(token
, origin
, entry_path
,
474 recursive
, persistent
, callback
,
475 notification_callback
)));
476 return AbortCallback();
479 void ProvidedFileSystem::RemoveWatcher(
481 const base::FilePath
& entry_path
,
483 const storage::AsyncFileUtil::StatusCallback
& callback
) {
484 const size_t token
= watcher_queue_
.NewToken();
485 watcher_queue_
.Enqueue(
486 token
, base::Bind(&ProvidedFileSystem::RemoveWatcherInQueue
,
487 base::Unretained(this), // Outlived by the queue.
488 token
, origin
, entry_path
, recursive
, callback
));
491 const ProvidedFileSystemInfo
& ProvidedFileSystem::GetFileSystemInfo() const {
492 return file_system_info_
;
495 RequestManager
* ProvidedFileSystem::GetRequestManager() {
496 return request_manager_
.get();
499 Watchers
* ProvidedFileSystem::GetWatchers() {
503 const OpenedFiles
& ProvidedFileSystem::GetOpenedFiles() const {
504 return opened_files_
;
507 void ProvidedFileSystem::AddObserver(ProvidedFileSystemObserver
* observer
) {
509 observers_
.AddObserver(observer
);
512 void ProvidedFileSystem::RemoveObserver(ProvidedFileSystemObserver
* observer
) {
514 observers_
.RemoveObserver(observer
);
517 void ProvidedFileSystem::Notify(
518 const base::FilePath
& entry_path
,
520 storage::WatcherManager::ChangeType change_type
,
521 scoped_ptr
<ProvidedFileSystemObserver::Changes
> changes
,
522 const std::string
& tag
,
523 const storage::AsyncFileUtil::StatusCallback
& callback
) {
524 const size_t token
= watcher_queue_
.NewToken();
525 watcher_queue_
.Enqueue(
526 token
, base::Bind(&ProvidedFileSystem::NotifyInQueue
,
527 base::Unretained(this), // Outlived by the queue.
528 base::Passed(make_scoped_ptr(new NotifyInQueueArgs(
529 token
, entry_path
, recursive
, change_type
,
530 changes
.Pass(), tag
, callback
)))));
533 void ProvidedFileSystem::Configure(
534 const storage::AsyncFileUtil::StatusCallback
& callback
) {
535 const int request_id
= request_manager_
->CreateRequest(
537 scoped_ptr
<RequestManager::HandlerInterface
>(new operations::Configure(
538 event_router_
, file_system_info_
, callback
)));
540 callback
.Run(base::File::FILE_ERROR_SECURITY
);
543 void ProvidedFileSystem::Abort(int operation_request_id
) {
544 request_manager_
->RejectRequest(operation_request_id
,
545 make_scoped_ptr(new RequestValue()),
546 base::File::FILE_ERROR_ABORT
);
547 if (!request_manager_
->CreateRequest(
549 scoped_ptr
<RequestManager::HandlerInterface
>(new operations::Abort(
550 event_router_
, file_system_info_
, operation_request_id
,
551 base::Bind(&EmptyStatusCallback
))))) {
552 LOG(ERROR
) << "Failed to create an abort request.";
556 AbortCallback
ProvidedFileSystem::AddWatcherInQueue(
557 const AddWatcherInQueueArgs
& args
) {
558 if (args
.persistent
&& (!file_system_info_
.supports_notify_tag() ||
559 !args
.notification_callback
.is_null())) {
560 OnAddWatcherInQueueCompleted(args
.token
, args
.entry_path
, args
.recursive
,
561 Subscriber(), args
.callback
,
562 base::File::FILE_ERROR_INVALID_OPERATION
);
563 return AbortCallback();
566 // Create a candidate subscriber. This could be done in OnAddWatcherCompleted,
567 // but base::Bind supports only up to 7 arguments.
568 Subscriber subscriber
;
569 subscriber
.origin
= args
.origin
;
570 subscriber
.persistent
= args
.persistent
;
571 subscriber
.notification_callback
= args
.notification_callback
;
573 const WatcherKey
key(args
.entry_path
, args
.recursive
);
574 const Watchers::const_iterator it
= watchers_
.find(key
);
575 if (it
!= watchers_
.end()) {
576 const bool exists
= it
->second
.subscribers
.find(args
.origin
) !=
577 it
->second
.subscribers
.end();
578 OnAddWatcherInQueueCompleted(
579 args
.token
, args
.entry_path
, args
.recursive
, subscriber
, args
.callback
,
580 exists
? base::File::FILE_ERROR_EXISTS
: base::File::FILE_OK
);
581 return AbortCallback();
584 const int request_id
= request_manager_
->CreateRequest(
586 scoped_ptr
<RequestManager::HandlerInterface
>(new operations::AddWatcher(
587 event_router_
, file_system_info_
, args
.entry_path
, args
.recursive
,
588 base::Bind(&ProvidedFileSystem::OnAddWatcherInQueueCompleted
,
589 weak_ptr_factory_
.GetWeakPtr(), args
.token
,
590 args
.entry_path
, args
.recursive
, subscriber
,
594 OnAddWatcherInQueueCompleted(args
.token
, args
.entry_path
, args
.recursive
,
595 subscriber
, args
.callback
,
596 base::File::FILE_ERROR_SECURITY
);
599 return AbortCallback();
602 AbortCallback
ProvidedFileSystem::RemoveWatcherInQueue(
605 const base::FilePath
& entry_path
,
607 const storage::AsyncFileUtil::StatusCallback
& callback
) {
608 const WatcherKey
key(entry_path
, recursive
);
609 const Watchers::iterator it
= watchers_
.find(key
);
610 if (it
== watchers_
.end() ||
611 it
->second
.subscribers
.find(origin
) == it
->second
.subscribers
.end()) {
612 OnRemoveWatcherInQueueCompleted(token
, origin
, key
, callback
,
613 false /* extension_response */,
614 base::File::FILE_ERROR_NOT_FOUND
);
615 return AbortCallback();
618 // If there are other subscribers, then do not remove the observer, but simply
620 if (it
->second
.subscribers
.size() > 1) {
621 OnRemoveWatcherInQueueCompleted(token
, origin
, key
, callback
,
622 false /* extension_response */,
623 base::File::FILE_OK
);
624 return AbortCallback();
627 // Otherwise, emit an event, and remove the watcher.
628 request_manager_
->CreateRequest(
630 scoped_ptr
<RequestManager::HandlerInterface
>(
631 new operations::RemoveWatcher(
632 event_router_
, file_system_info_
, entry_path
, recursive
,
633 base::Bind(&ProvidedFileSystem::OnRemoveWatcherInQueueCompleted
,
634 weak_ptr_factory_
.GetWeakPtr(), token
, origin
, key
,
635 callback
, true /* extension_response */))));
637 return AbortCallback();
640 AbortCallback
ProvidedFileSystem::NotifyInQueue(
641 scoped_ptr
<NotifyInQueueArgs
> args
) {
642 const WatcherKey
key(args
->entry_path
, args
->recursive
);
643 const auto& watcher_it
= watchers_
.find(key
);
644 if (watcher_it
== watchers_
.end()) {
645 OnNotifyInQueueCompleted(args
.Pass(), base::File::FILE_ERROR_NOT_FOUND
);
646 return AbortCallback();
649 // The tag must be provided if and only if it's explicitly supported.
650 if (file_system_info_
.supports_notify_tag() == args
->tag
.empty()) {
651 OnNotifyInQueueCompleted(args
.Pass(),
652 base::File::FILE_ERROR_INVALID_OPERATION
);
653 return AbortCallback();
656 // It's illegal to provide a tag which is not unique.
657 if (!args
->tag
.empty() && args
->tag
== watcher_it
->second
.last_tag
) {
658 OnNotifyInQueueCompleted(args
.Pass(),
659 base::File::FILE_ERROR_INVALID_OPERATION
);
660 return AbortCallback();
663 // The object is owned by AutoUpdated, so the reference is valid as long as
664 // callbacks created with AutoUpdater::CreateCallback().
665 const ProvidedFileSystemObserver::Changes
& changes_ref
= *args
->changes
.get();
666 const storage::WatcherManager::ChangeType change_type
= args
->change_type
;
668 scoped_refptr
<AutoUpdater
> auto_updater(
669 new AutoUpdater(base::Bind(&ProvidedFileSystem::OnNotifyInQueueCompleted
,
670 weak_ptr_factory_
.GetWeakPtr(),
671 base::Passed(&args
), base::File::FILE_OK
)));
673 // Call all notification callbacks (if any).
674 for (const auto& subscriber_it
: watcher_it
->second
.subscribers
) {
675 const storage::WatcherManager::NotificationCallback
& notification_callback
=
676 subscriber_it
.second
.notification_callback
;
677 if (!notification_callback
.is_null())
678 notification_callback
.Run(change_type
);
681 // Notify all observers.
682 FOR_EACH_OBSERVER(ProvidedFileSystemObserver
,
684 OnWatcherChanged(file_system_info_
,
688 auto_updater
->CreateCallback()));
690 return AbortCallback();
693 base::WeakPtr
<ProvidedFileSystemInterface
> ProvidedFileSystem::GetWeakPtr() {
694 return weak_ptr_factory_
.GetWeakPtr();
697 void ProvidedFileSystem::OnAddWatcherInQueueCompleted(
699 const base::FilePath
& entry_path
,
701 const Subscriber
& subscriber
,
702 const storage::AsyncFileUtil::StatusCallback
& callback
,
703 base::File::Error result
) {
704 if (result
!= base::File::FILE_OK
) {
705 callback
.Run(result
);
706 watcher_queue_
.Complete(token
);
710 const WatcherKey
key(entry_path
, recursive
);
711 const Watchers::iterator it
= watchers_
.find(key
);
712 if (it
!= watchers_
.end()) {
713 callback
.Run(base::File::FILE_OK
);
714 watcher_queue_
.Complete(token
);
718 Watcher
* const watcher
= &watchers_
[key
];
719 watcher
->entry_path
= entry_path
;
720 watcher
->recursive
= recursive
;
721 watcher
->subscribers
[subscriber
.origin
] = subscriber
;
723 FOR_EACH_OBSERVER(ProvidedFileSystemObserver
,
725 OnWatcherListChanged(file_system_info_
, watchers_
));
727 callback
.Run(base::File::FILE_OK
);
728 watcher_queue_
.Complete(token
);
731 void ProvidedFileSystem::OnRemoveWatcherInQueueCompleted(
734 const WatcherKey
& key
,
735 const storage::AsyncFileUtil::StatusCallback
& callback
,
736 bool extension_response
,
737 base::File::Error result
) {
738 if (!extension_response
&& result
!= base::File::FILE_OK
) {
739 watcher_queue_
.Complete(token
);
740 callback
.Run(result
);
744 // Even if the extension returns an error, the callback is called with base::
746 const auto it
= watchers_
.find(key
);
747 DCHECK(it
!= watchers_
.end());
748 DCHECK(it
->second
.subscribers
.find(origin
) != it
->second
.subscribers
.end());
750 it
->second
.subscribers
.erase(origin
);
752 FOR_EACH_OBSERVER(ProvidedFileSystemObserver
, observers_
,
753 OnWatcherListChanged(file_system_info_
, watchers_
));
755 // If there are no more subscribers, then remove the watcher.
756 if (!it
->second
.subscribers
.size())
759 callback
.Run(base::File::FILE_OK
);
760 watcher_queue_
.Complete(token
);
763 void ProvidedFileSystem::OnNotifyInQueueCompleted(
764 scoped_ptr
<NotifyInQueueArgs
> args
,
765 base::File::Error result
) {
766 if (result
!= base::File::FILE_OK
) {
767 args
->callback
.Run(result
);
768 watcher_queue_
.Complete(args
->token
);
772 // Check if the entry is still watched.
773 const WatcherKey
key(args
->entry_path
, args
->recursive
);
774 const Watchers::iterator it
= watchers_
.find(key
);
775 if (it
== watchers_
.end()) {
776 args
->callback
.Run(base::File::FILE_ERROR_NOT_FOUND
);
777 watcher_queue_
.Complete(args
->token
);
781 it
->second
.last_tag
= args
->tag
;
783 FOR_EACH_OBSERVER(ProvidedFileSystemObserver
,
785 OnWatcherTagUpdated(file_system_info_
, it
->second
));
787 // If the watched entry is deleted, then remove the watcher.
788 if (args
->change_type
== storage::WatcherManager::DELETED
) {
789 // Make a copy, since the |it| iterator will get invalidated on the last
791 Subscribers subscribers
= it
->second
.subscribers
;
792 for (const auto& subscriber_it
: subscribers
) {
793 RemoveWatcher(subscriber_it
.second
.origin
, args
->entry_path
,
794 args
->recursive
, base::Bind(&EmptyStatusCallback
));
798 args
->callback
.Run(base::File::FILE_OK
);
799 watcher_queue_
.Complete(args
->token
);
802 void ProvidedFileSystem::OnOpenFileCompleted(const base::FilePath
& file_path
,
804 const OpenFileCallback
& callback
,
806 base::File::Error result
) {
807 if (result
!= base::File::FILE_OK
) {
808 callback
.Run(file_handle
, result
);
812 opened_files_
[file_handle
] = OpenedFile(file_path
, mode
);
813 callback
.Run(file_handle
, base::File::FILE_OK
);
816 void ProvidedFileSystem::OnCloseFileCompleted(
818 const storage::AsyncFileUtil::StatusCallback
& callback
,
819 base::File::Error result
) {
820 // Closing files is final. Even if an error happened, we remove it from the
821 // list of opened files.
822 opened_files_
.erase(file_handle
);
823 callback
.Run(result
);
826 } // namespace file_system_provider
827 } // namespace chromeos