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();
297 return base::Bind(&ProvidedFileSystem::Abort
, weak_ptr_factory_
.GetWeakPtr(),
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 if (!request_manager_
->CreateRequest(
546 scoped_ptr
<RequestManager::HandlerInterface
>(new operations::Abort(
547 event_router_
, file_system_info_
, operation_request_id
,
548 base::Bind(&ProvidedFileSystem::OnAbortCompleted
,
549 weak_ptr_factory_
.GetWeakPtr(),
550 operation_request_id
))))) {
551 // If the aborting event is not handled, then the operation should simply
552 // be not aborted. Instead we'll wait until it completes.
553 LOG(ERROR
) << "Failed to create an abort request.";
557 void ProvidedFileSystem::OnAbortCompleted(int operation_request_id
,
558 base::File::Error result
) {
559 if (result
!= base::File::FILE_OK
) {
560 // If an error in aborting happens, then do not abort the request in the
561 // request manager, as the operation is supposed to complete. The only case
562 // it wouldn't complete is if there is a bug in the extension code, and
563 // the extension never calls the callback. We consiously *do not* handle
564 // bugs in extensions here.
567 request_manager_
->RejectRequest(operation_request_id
,
568 make_scoped_ptr(new RequestValue()),
569 base::File::FILE_ERROR_ABORT
);
572 AbortCallback
ProvidedFileSystem::AddWatcherInQueue(
573 const AddWatcherInQueueArgs
& args
) {
574 if (args
.persistent
&& (!file_system_info_
.supports_notify_tag() ||
575 !args
.notification_callback
.is_null())) {
576 OnAddWatcherInQueueCompleted(args
.token
, args
.entry_path
, args
.recursive
,
577 Subscriber(), args
.callback
,
578 base::File::FILE_ERROR_INVALID_OPERATION
);
579 return AbortCallback();
582 // Create a candidate subscriber. This could be done in OnAddWatcherCompleted,
583 // but base::Bind supports only up to 7 arguments.
584 Subscriber subscriber
;
585 subscriber
.origin
= args
.origin
;
586 subscriber
.persistent
= args
.persistent
;
587 subscriber
.notification_callback
= args
.notification_callback
;
589 const WatcherKey
key(args
.entry_path
, args
.recursive
);
590 const Watchers::const_iterator it
= watchers_
.find(key
);
591 if (it
!= watchers_
.end()) {
592 const bool exists
= it
->second
.subscribers
.find(args
.origin
) !=
593 it
->second
.subscribers
.end();
594 OnAddWatcherInQueueCompleted(
595 args
.token
, args
.entry_path
, args
.recursive
, subscriber
, args
.callback
,
596 exists
? base::File::FILE_ERROR_EXISTS
: base::File::FILE_OK
);
597 return AbortCallback();
600 const int request_id
= request_manager_
->CreateRequest(
602 scoped_ptr
<RequestManager::HandlerInterface
>(new operations::AddWatcher(
603 event_router_
, file_system_info_
, args
.entry_path
, args
.recursive
,
604 base::Bind(&ProvidedFileSystem::OnAddWatcherInQueueCompleted
,
605 weak_ptr_factory_
.GetWeakPtr(), args
.token
,
606 args
.entry_path
, args
.recursive
, subscriber
,
610 OnAddWatcherInQueueCompleted(args
.token
, args
.entry_path
, args
.recursive
,
611 subscriber
, args
.callback
,
612 base::File::FILE_ERROR_SECURITY
);
615 return AbortCallback();
618 AbortCallback
ProvidedFileSystem::RemoveWatcherInQueue(
621 const base::FilePath
& entry_path
,
623 const storage::AsyncFileUtil::StatusCallback
& callback
) {
624 const WatcherKey
key(entry_path
, recursive
);
625 const Watchers::iterator it
= watchers_
.find(key
);
626 if (it
== watchers_
.end() ||
627 it
->second
.subscribers
.find(origin
) == it
->second
.subscribers
.end()) {
628 OnRemoveWatcherInQueueCompleted(token
, origin
, key
, callback
,
629 false /* extension_response */,
630 base::File::FILE_ERROR_NOT_FOUND
);
631 return AbortCallback();
634 // If there are other subscribers, then do not remove the observer, but simply
636 if (it
->second
.subscribers
.size() > 1) {
637 OnRemoveWatcherInQueueCompleted(token
, origin
, key
, callback
,
638 false /* extension_response */,
639 base::File::FILE_OK
);
640 return AbortCallback();
643 // Otherwise, emit an event, and remove the watcher.
644 request_manager_
->CreateRequest(
646 scoped_ptr
<RequestManager::HandlerInterface
>(
647 new operations::RemoveWatcher(
648 event_router_
, file_system_info_
, entry_path
, recursive
,
649 base::Bind(&ProvidedFileSystem::OnRemoveWatcherInQueueCompleted
,
650 weak_ptr_factory_
.GetWeakPtr(), token
, origin
, key
,
651 callback
, true /* extension_response */))));
653 return AbortCallback();
656 AbortCallback
ProvidedFileSystem::NotifyInQueue(
657 scoped_ptr
<NotifyInQueueArgs
> args
) {
658 const WatcherKey
key(args
->entry_path
, args
->recursive
);
659 const auto& watcher_it
= watchers_
.find(key
);
660 if (watcher_it
== watchers_
.end()) {
661 OnNotifyInQueueCompleted(args
.Pass(), base::File::FILE_ERROR_NOT_FOUND
);
662 return AbortCallback();
665 // The tag must be provided if and only if it's explicitly supported.
666 if (file_system_info_
.supports_notify_tag() == args
->tag
.empty()) {
667 OnNotifyInQueueCompleted(args
.Pass(),
668 base::File::FILE_ERROR_INVALID_OPERATION
);
669 return AbortCallback();
672 // It's illegal to provide a tag which is not unique.
673 if (!args
->tag
.empty() && args
->tag
== watcher_it
->second
.last_tag
) {
674 OnNotifyInQueueCompleted(args
.Pass(),
675 base::File::FILE_ERROR_INVALID_OPERATION
);
676 return AbortCallback();
679 // The object is owned by AutoUpdated, so the reference is valid as long as
680 // callbacks created with AutoUpdater::CreateCallback().
681 const ProvidedFileSystemObserver::Changes
& changes_ref
= *args
->changes
.get();
682 const storage::WatcherManager::ChangeType change_type
= args
->change_type
;
684 scoped_refptr
<AutoUpdater
> auto_updater(
685 new AutoUpdater(base::Bind(&ProvidedFileSystem::OnNotifyInQueueCompleted
,
686 weak_ptr_factory_
.GetWeakPtr(),
687 base::Passed(&args
), base::File::FILE_OK
)));
689 // Call all notification callbacks (if any).
690 for (const auto& subscriber_it
: watcher_it
->second
.subscribers
) {
691 const storage::WatcherManager::NotificationCallback
& notification_callback
=
692 subscriber_it
.second
.notification_callback
;
693 if (!notification_callback
.is_null())
694 notification_callback
.Run(change_type
);
697 // Notify all observers.
698 FOR_EACH_OBSERVER(ProvidedFileSystemObserver
,
700 OnWatcherChanged(file_system_info_
,
704 auto_updater
->CreateCallback()));
706 return AbortCallback();
709 base::WeakPtr
<ProvidedFileSystemInterface
> ProvidedFileSystem::GetWeakPtr() {
710 return weak_ptr_factory_
.GetWeakPtr();
713 void ProvidedFileSystem::OnAddWatcherInQueueCompleted(
715 const base::FilePath
& entry_path
,
717 const Subscriber
& subscriber
,
718 const storage::AsyncFileUtil::StatusCallback
& callback
,
719 base::File::Error result
) {
720 if (result
!= base::File::FILE_OK
) {
721 callback
.Run(result
);
722 watcher_queue_
.Complete(token
);
726 const WatcherKey
key(entry_path
, recursive
);
727 const Watchers::iterator it
= watchers_
.find(key
);
728 if (it
!= watchers_
.end()) {
729 callback
.Run(base::File::FILE_OK
);
730 watcher_queue_
.Complete(token
);
734 Watcher
* const watcher
= &watchers_
[key
];
735 watcher
->entry_path
= entry_path
;
736 watcher
->recursive
= recursive
;
737 watcher
->subscribers
[subscriber
.origin
] = subscriber
;
739 FOR_EACH_OBSERVER(ProvidedFileSystemObserver
,
741 OnWatcherListChanged(file_system_info_
, watchers_
));
743 callback
.Run(base::File::FILE_OK
);
744 watcher_queue_
.Complete(token
);
747 void ProvidedFileSystem::OnRemoveWatcherInQueueCompleted(
750 const WatcherKey
& key
,
751 const storage::AsyncFileUtil::StatusCallback
& callback
,
752 bool extension_response
,
753 base::File::Error result
) {
754 if (!extension_response
&& result
!= base::File::FILE_OK
) {
755 watcher_queue_
.Complete(token
);
756 callback
.Run(result
);
760 // Even if the extension returns an error, the callback is called with base::
762 const auto it
= watchers_
.find(key
);
763 DCHECK(it
!= watchers_
.end());
764 DCHECK(it
->second
.subscribers
.find(origin
) != it
->second
.subscribers
.end());
766 it
->second
.subscribers
.erase(origin
);
768 FOR_EACH_OBSERVER(ProvidedFileSystemObserver
, observers_
,
769 OnWatcherListChanged(file_system_info_
, watchers_
));
771 // If there are no more subscribers, then remove the watcher.
772 if (!it
->second
.subscribers
.size())
775 callback
.Run(base::File::FILE_OK
);
776 watcher_queue_
.Complete(token
);
779 void ProvidedFileSystem::OnNotifyInQueueCompleted(
780 scoped_ptr
<NotifyInQueueArgs
> args
,
781 base::File::Error result
) {
782 if (result
!= base::File::FILE_OK
) {
783 args
->callback
.Run(result
);
784 watcher_queue_
.Complete(args
->token
);
788 // Check if the entry is still watched.
789 const WatcherKey
key(args
->entry_path
, args
->recursive
);
790 const Watchers::iterator it
= watchers_
.find(key
);
791 if (it
== watchers_
.end()) {
792 args
->callback
.Run(base::File::FILE_ERROR_NOT_FOUND
);
793 watcher_queue_
.Complete(args
->token
);
797 it
->second
.last_tag
= args
->tag
;
799 FOR_EACH_OBSERVER(ProvidedFileSystemObserver
,
801 OnWatcherTagUpdated(file_system_info_
, it
->second
));
803 // If the watched entry is deleted, then remove the watcher.
804 if (args
->change_type
== storage::WatcherManager::DELETED
) {
805 // Make a copy, since the |it| iterator will get invalidated on the last
807 Subscribers subscribers
= it
->second
.subscribers
;
808 for (const auto& subscriber_it
: subscribers
) {
809 RemoveWatcher(subscriber_it
.second
.origin
, args
->entry_path
,
810 args
->recursive
, base::Bind(&EmptyStatusCallback
));
814 args
->callback
.Run(base::File::FILE_OK
);
815 watcher_queue_
.Complete(args
->token
);
818 void ProvidedFileSystem::OnOpenFileCompleted(const base::FilePath
& file_path
,
820 const OpenFileCallback
& callback
,
822 base::File::Error result
) {
823 if (result
!= base::File::FILE_OK
) {
824 callback
.Run(file_handle
, result
);
828 opened_files_
[file_handle
] = OpenedFile(file_path
, mode
);
829 callback
.Run(file_handle
, base::File::FILE_OK
);
832 void ProvidedFileSystem::OnCloseFileCompleted(
834 const storage::AsyncFileUtil::StatusCallback
& callback
,
835 base::File::Error result
) {
836 // Closing files is final. Even if an error happened, we remove it from the
837 // list of opened files.
838 opened_files_
.erase(file_handle
);
839 callback
.Run(result
);
842 } // namespace file_system_provider
843 } // namespace chromeos