11320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// Copyright 2014 The Chromium Authors. All rights reserved.
21320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// Use of this source code is governed by a BSD-style license that can be
31320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// found in the LICENSE file.
41320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
51320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "chrome/browser/extensions/api/file_system/entry_watcher_service.h"
61320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
71320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "base/thread_task_runner_handle.h"
81320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "chrome/browser/extensions/extension_util.h"
91320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "chrome/browser/profiles/profile.h"
101320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "chrome/common/extensions/api/file_system.h"
111320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "components/keyed_service/content/browser_context_dependency_manager.h"
121320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "content/public/browser/browser_context.h"
131320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "content/public/browser/browser_thread.h"
141320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "content/public/browser/storage_partition.h"
151320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "extensions/browser/event_router.h"
161320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "storage/browser/fileapi/file_system_context.h"
171320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
181320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccinamespace extensions {
191320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccinamespace {
201320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
211320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// Default implementation for dispatching an event. Can be replaced for unit
221320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// tests by EntryWatcherService::SetDispatchEventImplForTesting().
231320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid DispatchEventImpl(EventRouter* event_router,
241320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                       const std::string& extension_id,
251320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                       scoped_ptr<Event> event) {
261320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  event_router->DispatchEventToExtension(extension_id, event.Pass());
271320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
281320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
291320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// Default implementation for acquiring a file system context for a specific
301320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// |extension_id| and |context|.
311320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccistorage::FileSystemContext* GetFileSystemContextImpl(
321320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    const std::string& extension_id,
331320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    content::BrowserContext* context) {
341320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  const GURL site = util::GetSiteForExtensionId(extension_id, context);
351320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  return content::BrowserContext::GetStoragePartitionForSite(context, site)
361320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      ->GetFileSystemContext();
371320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
381320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
391320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}  // namespace
401320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
411320f92c476a1ad9d19dba2a48c72b75566198e9Primiano TucciEntryWatcherService::EntryWatcherService(content::BrowserContext* context)
421320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    : context_(context),
431320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      dispatch_event_impl_(
441320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci          base::Bind(&DispatchEventImpl, EventRouter::Get(context))),
451320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      get_file_system_context_impl_(base::Bind(&GetFileSystemContextImpl)),
461320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      observing_(this),
471320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      weak_ptr_factory_(this) {
481320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // TODO(mtomasz): Restore persistent watchers.
491320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
501320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
511320f92c476a1ad9d19dba2a48c72b75566198e9Primiano TucciEntryWatcherService::~EntryWatcherService() {
521320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
531320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
541320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid EntryWatcherService::SetDispatchEventImplForTesting(
551320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    const DispatchEventImplCallback& callback) {
561320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  dispatch_event_impl_ = callback;
571320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
581320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
591320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid EntryWatcherService::SetGetFileSystemContextImplForTesting(
601320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    const GetFileSystemContextImplCallback& callback) {
611320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  get_file_system_context_impl_ = callback;
621320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
631320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
641320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid EntryWatcherService::WatchDirectory(
651320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    const std::string& extension_id,
661320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    const storage::FileSystemURL& url,
671320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    bool recursive,
681320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    const storage::WatcherManager::StatusCallback& callback) {
691320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // TODO(mtomasz): Add support for recursive watchers.
701320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (recursive) {
711320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    base::ThreadTaskRunnerHandle::Get()->PostTask(
721320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        FROM_HERE,
731320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        base::Bind(callback, base::File::FILE_ERROR_INVALID_OPERATION));
741320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    return;
751320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
761320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
771320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  storage::FileSystemContext* const context =
781320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      get_file_system_context_impl_.Run(extension_id, context_);
791320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  DCHECK(context);
801320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
811320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  storage::WatcherManager* const watcher_manager =
821320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      context->GetWatcherManager(url.type());
831320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (!watcher_manager) {
841320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // Post a task instead of calling the callback directly, since the caller
851320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // may expect the callback to be called asynchronously.
861320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    base::ThreadTaskRunnerHandle::Get()->PostTask(
871320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        FROM_HERE,
881320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        base::Bind(callback, base::File::FILE_ERROR_INVALID_OPERATION));
891320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    return;
901320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
911320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
921320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // Passing a pointer to WatcherManager is safe, since the pointer is required
931320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // to be valid until shutdown.
941320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  context->default_file_task_runner()->PostNonNestableTask(
951320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      FROM_HERE,
961320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      base::Bind(&storage::WatcherManager::WatchDirectory,
971320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                 base::Unretained(watcher_manager),  // Outlives the service.
981320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                 url,
991320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                 recursive,
1001320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                 base::Bind(&EntryWatcherService::OnWatchDirectoryCompleted,
1011320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                            weak_ptr_factory_.GetWeakPtr(),
1021320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                            watcher_manager,  // Outlives the service.
1031320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                            extension_id,
1041320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                            url,
1051320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                            recursive,
1061320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                            callback)));
1071320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
1081320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1091320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid EntryWatcherService::UnwatchEntry(
1101320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    const std::string& extension_id,
1111320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    const storage::FileSystemURL& url,
1121320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    const storage::WatcherManager::StatusCallback& callback) {
1131320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  storage::FileSystemContext* const context =
1141320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      get_file_system_context_impl_.Run(extension_id, context_);
1151320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  DCHECK(context);
1161320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1171320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  storage::WatcherManager* const watcher_manager =
1181320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      context->GetWatcherManager(url.type());
1191320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (!watcher_manager) {
1201320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    base::ThreadTaskRunnerHandle::Get()->PostTask(
1211320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        FROM_HERE,
1221320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        base::Bind(callback, base::File::FILE_ERROR_INVALID_OPERATION));
1231320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    return;
1241320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
1251320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1261320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // Passing a pointer to WatcherManager is safe, since the pointer is required
1271320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // to be valid until shutdown.
1281320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  context->default_file_task_runner()->PostNonNestableTask(
1291320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      FROM_HERE,
1301320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      base::Bind(&storage::WatcherManager::UnwatchEntry,
1311320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                 base::Unretained(watcher_manager),  // Outlives the service.
1321320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                 url,
1331320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                 base::Bind(&EntryWatcherService::OnUnwatchEntryCompleted,
1341320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                            weak_ptr_factory_.GetWeakPtr(),
1351320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                            extension_id,
1361320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                            url,
1371320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                            callback)));
1381320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
1391320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1401320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccistd::vector<storage::FileSystemURL> EntryWatcherService::GetWatchedEntries(
1411320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    const std::string& extension_id) {
1421320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  std::vector<storage::FileSystemURL> result;
1431320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  for (WatcherMap::const_iterator it = watchers_.begin(); it != watchers_.end();
1441320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci       ++it) {
1451320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    const std::map<std::string, EntryWatcher>::const_iterator watcher_it =
1461320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        it->second.find(extension_id);
1471320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    if (watcher_it != it->second.end())
1481320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      result.push_back(watcher_it->second.url);
1491320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
1501320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1511320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  return result;
1521320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
1531320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1541320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid EntryWatcherService::OnEntryChanged(const storage::FileSystemURL& url) {
1551320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  const WatcherMap::const_iterator it = watchers_.find(url);
1561320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  DCHECK(it != watchers_.end());
1571320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  for (std::map<std::string, EntryWatcher>::const_iterator watcher_it =
1581320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci           it->second.begin();
1591320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci       watcher_it != it->second.end();
1601320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci       ++watcher_it) {
1611320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    const std::string& extension_id = watcher_it->first;
1621320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    api::file_system::EntryChangedEvent event;
1631320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    dispatch_event_impl_.Run(
1641320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        extension_id,
1651320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        make_scoped_ptr(
1661320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci            new Event(api::file_system::OnEntryChanged::kEventName,
1671320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                      api::file_system::OnEntryChanged::Create(event))));
1681320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
1691320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
1701320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1711320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid EntryWatcherService::OnEntryRemoved(const storage::FileSystemURL& url) {
1721320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  WatcherMap::const_iterator it = watchers_.find(url);
1731320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  DCHECK(it != watchers_.end());
1741320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  for (std::map<std::string, EntryWatcher>::const_iterator watcher_it =
1751320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci           it->second.begin();
1761320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci       watcher_it != it->second.end();
1771320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci       ++watcher_it) {
1781320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    const std::string& extension_id = watcher_it->first;
1791320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    api::file_system::EntryRemovedEvent event;
1801320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    dispatch_event_impl_.Run(
1811320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        extension_id,
1821320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        make_scoped_ptr(
1831320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci            new Event(api::file_system::OnEntryRemoved::kEventName,
1841320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                      api::file_system::OnEntryRemoved::Create(event))));
1851320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
1861320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
1871320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1881320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid EntryWatcherService::OnWatchDirectoryCompleted(
1891320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    storage::WatcherManager* watcher_manager,
1901320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    const std::string& extension_id,
1911320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    const storage::FileSystemURL& url,
1921320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    bool recursive,
1931320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    const storage::WatcherManager::StatusCallback& callback,
1941320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    base::File::Error result) {
1951320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (result != base::File::FILE_OK) {
1961320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    callback.Run(result);
1971320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    return;
1981320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
1991320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
2001320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  storage::FileSystemContext* const context =
2011320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      get_file_system_context_impl_.Run(extension_id, context_);
2021320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  DCHECK(context);
2031320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
2041320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // Observe the manager if not observed yet.
2051320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (!observing_.IsObserving(watcher_manager))
2061320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    observing_.Add(watcher_manager);
2071320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
2081320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  watchers_[url][extension_id] =
2091320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      EntryWatcher(url, true /* directory */, recursive);
2101320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
2111320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // TODO(mtomasz): Save in preferences.
2121320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
2131320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  callback.Run(base::File::FILE_OK);
2141320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
2151320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
2161320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid EntryWatcherService::OnUnwatchEntryCompleted(
2171320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    const std::string& extension_id,
2181320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    const storage::FileSystemURL& url,
2191320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    const storage::WatcherManager::StatusCallback& callback,
2201320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    base::File::Error result) {
2211320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (result != base::File::FILE_OK) {
2221320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    callback.Run(result);
2231320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    return;
2241320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
2251320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
2261320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (watchers_[url].erase(extension_id) == 0) {
2271320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    callback.Run(base::File::FILE_ERROR_NOT_FOUND);
2281320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    return;
2291320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
2301320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
2311320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (watchers_[url].empty())
2321320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    watchers_.erase(url);
2331320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
2341320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // TODO(mtomasz): Save in preferences.
2351320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
2361320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  callback.Run(base::File::FILE_OK);
2371320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
2381320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
2391320f92c476a1ad9d19dba2a48c72b75566198e9Primiano TucciEntryWatcherService::EntryWatcher::EntryWatcher()
2401320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    : directory(false), recursive(false) {
2411320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
2421320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
2431320f92c476a1ad9d19dba2a48c72b75566198e9Primiano TucciEntryWatcherService::EntryWatcher::EntryWatcher(
2441320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    const storage::FileSystemURL& url,
2451320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    bool directory,
2461320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    bool recursive)
2471320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    : url(url), directory(directory), recursive(recursive) {
2481320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
2491320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
2501320f92c476a1ad9d19dba2a48c72b75566198e9Primiano TucciEntryWatcherService::EntryWatcher::~EntryWatcher() {
2511320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
2521320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
2531320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}  // namespace extensions
254