Commit b75244fd authored by mtomasz's avatar mtomasz Committed by Commit bot

[ew] Add basic classes.

This patch adds a EntryWatcherService, which is a bridge between extensions and
fileapi. Also, WatcherManager interface has been created to let backends
implement their own watching logic.

Note, that EntryWatcherService is not wired up to File System API yet. Also,
a lot of features are missing.

TBR=noamsml, jcivelli
TEST=unit_tests: *EntryWatcherService*
BUG=261491

Review URL: https://codereview.chromium.org/452043003

Cr-Commit-Position: refs/heads/master@{#292327}
parent eacf155f
...@@ -80,4 +80,10 @@ FileSystemBackendDelegate::CreateFileStreamWriter( ...@@ -80,4 +80,10 @@ FileSystemBackendDelegate::CreateFileStreamWriter(
offset)); offset));
} }
storage::WatcherManager* FileSystemBackendDelegate::GetWatcherManager(
const storage::FileSystemURL& url) {
NOTIMPLEMENTED();
return NULL;
}
} // namespace drive } // namespace drive
...@@ -11,6 +11,11 @@ ...@@ -11,6 +11,11 @@
namespace storage { namespace storage {
class AsyncFileUtil; class AsyncFileUtil;
class FileSystemContext;
class FileStreamReader;
class FileSystemURL;
class FileStreamWriter;
class WatcherManager;
} // namespace storage } // namespace storage
namespace drive { namespace drive {
...@@ -34,6 +39,8 @@ class FileSystemBackendDelegate : public chromeos::FileSystemBackendDelegate { ...@@ -34,6 +39,8 @@ class FileSystemBackendDelegate : public chromeos::FileSystemBackendDelegate {
const storage::FileSystemURL& url, const storage::FileSystemURL& url,
int64 offset, int64 offset,
storage::FileSystemContext* context) OVERRIDE; storage::FileSystemContext* context) OVERRIDE;
virtual storage::WatcherManager* GetWatcherManager(
const storage::FileSystemURL& url) OVERRIDE;
private: private:
scoped_ptr<storage::AsyncFileUtil> async_file_util_; scoped_ptr<storage::AsyncFileUtil> async_file_util_;
......
...@@ -63,5 +63,11 @@ scoped_ptr<storage::FileStreamWriter> BackendDelegate::CreateFileStreamWriter( ...@@ -63,5 +63,11 @@ scoped_ptr<storage::FileStreamWriter> BackendDelegate::CreateFileStreamWriter(
new FileStreamWriter(url, offset)); new FileStreamWriter(url, offset));
} }
storage::WatcherManager* BackendDelegate::GetWatcherManager(
const storage::FileSystemURL& url) {
NOTIMPLEMENTED();
return NULL;
}
} // namespace file_system_provider } // namespace file_system_provider
} // namespace chromeos } // namespace chromeos
...@@ -6,11 +6,17 @@ ...@@ -6,11 +6,17 @@
#define CHROME_BROWSER_CHROMEOS_FILE_SYSTEM_PROVIDER_FILEAPI_BACKEND_DELEGATE_H_ #define CHROME_BROWSER_CHROMEOS_FILE_SYSTEM_PROVIDER_FILEAPI_BACKEND_DELEGATE_H_
#include "base/basictypes.h" #include "base/basictypes.h"
#include "base/file_util.h"
#include "base/memory/scoped_ptr.h" #include "base/memory/scoped_ptr.h"
#include "chrome/browser/chromeos/fileapi/file_system_backend_delegate.h" #include "chrome/browser/chromeos/fileapi/file_system_backend_delegate.h"
namespace storage { namespace storage {
class AsyncFileUtil; class AsyncFileUtil;
class FileSystemContext;
class FileStreamReader;
class FileSystemURL;
class FileStreamWriter;
class WatcherManager;
} // namespace storage } // namespace storage
namespace chromeos { namespace chromeos {
...@@ -35,6 +41,8 @@ class BackendDelegate : public chromeos::FileSystemBackendDelegate { ...@@ -35,6 +41,8 @@ class BackendDelegate : public chromeos::FileSystemBackendDelegate {
const storage::FileSystemURL& url, const storage::FileSystemURL& url,
int64 offset, int64 offset,
storage::FileSystemContext* context) OVERRIDE; storage::FileSystemContext* context) OVERRIDE;
virtual storage::WatcherManager* GetWatcherManager(
const storage::FileSystemURL& url) OVERRIDE;
private: private:
scoped_ptr<storage::AsyncFileUtil> async_file_util_; scoped_ptr<storage::AsyncFileUtil> async_file_util_;
......
...@@ -249,6 +249,11 @@ storage::AsyncFileUtil* FileSystemBackend::GetAsyncFileUtil( ...@@ -249,6 +249,11 @@ storage::AsyncFileUtil* FileSystemBackend::GetAsyncFileUtil(
return NULL; return NULL;
} }
storage::WatcherManager* FileSystemBackend::GetWatcherManager(
storage::FileSystemType type) {
return NULL;
}
storage::CopyOrMoveFileValidatorFactory* storage::CopyOrMoveFileValidatorFactory*
FileSystemBackend::GetCopyOrMoveFileValidatorFactory( FileSystemBackend::GetCopyOrMoveFileValidatorFactory(
storage::FileSystemType type, storage::FileSystemType type,
......
...@@ -19,6 +19,7 @@ namespace storage { ...@@ -19,6 +19,7 @@ namespace storage {
class CopyOrMoveFileValidatorFactory; class CopyOrMoveFileValidatorFactory;
class ExternalMountPoints; class ExternalMountPoints;
class FileSystemURL; class FileSystemURL;
class WatcherManager;
} // namespace storage } // namespace storage
namespace chromeos { namespace chromeos {
...@@ -93,6 +94,8 @@ class FileSystemBackend : public storage::ExternalFileSystemBackend { ...@@ -93,6 +94,8 @@ class FileSystemBackend : public storage::ExternalFileSystemBackend {
const OpenFileSystemCallback& callback) OVERRIDE; const OpenFileSystemCallback& callback) OVERRIDE;
virtual storage::AsyncFileUtil* GetAsyncFileUtil( virtual storage::AsyncFileUtil* GetAsyncFileUtil(
storage::FileSystemType type) OVERRIDE; storage::FileSystemType type) OVERRIDE;
virtual storage::WatcherManager* GetWatcherManager(
storage::FileSystemType type) OVERRIDE;
virtual storage::CopyOrMoveFileValidatorFactory* virtual storage::CopyOrMoveFileValidatorFactory*
GetCopyOrMoveFileValidatorFactory(storage::FileSystemType type, GetCopyOrMoveFileValidatorFactory(storage::FileSystemType type,
base::File::Error* error_code) OVERRIDE; base::File::Error* error_code) OVERRIDE;
......
...@@ -16,8 +16,10 @@ class Time; ...@@ -16,8 +16,10 @@ class Time;
namespace storage { namespace storage {
class AsyncFileUtil; class AsyncFileUtil;
class FileSystemContext; class FileSystemContext;
class FileStreamReader;
class FileSystemURL; class FileSystemURL;
class FileStreamWriter; class FileStreamWriter;
class WatcherManager;
} // namespace storage } // namespace storage
namespace storage { namespace storage {
...@@ -27,7 +29,7 @@ class FileStreamReader; ...@@ -27,7 +29,7 @@ class FileStreamReader;
namespace chromeos { namespace chromeos {
// This is delegate interface to inject the implementation of the some methods // This is delegate interface to inject the implementation of the some methods
// of FileSystemBackend. The main goal is to inject Drive File System. // of FileSystemBackend.
class FileSystemBackendDelegate { class FileSystemBackendDelegate {
public: public:
virtual ~FileSystemBackendDelegate() {} virtual ~FileSystemBackendDelegate() {}
...@@ -48,6 +50,11 @@ class FileSystemBackendDelegate { ...@@ -48,6 +50,11 @@ class FileSystemBackendDelegate {
const storage::FileSystemURL& url, const storage::FileSystemURL& url,
int64 offset, int64 offset,
storage::FileSystemContext* context) = 0; storage::FileSystemContext* context) = 0;
// Called from the FileSystemWatcherService class. The returned pointer must
// stay valid until shutdown.
virtual storage::WatcherManager* GetWatcherManager(
const storage::FileSystemURL& url) = 0;
}; };
} // namespace chromeos } // namespace chromeos
......
...@@ -50,4 +50,10 @@ MTPFileSystemBackendDelegate::CreateFileStreamWriter( ...@@ -50,4 +50,10 @@ MTPFileSystemBackendDelegate::CreateFileStreamWriter(
return scoped_ptr<storage::FileStreamWriter>(); return scoped_ptr<storage::FileStreamWriter>();
} }
storage::WatcherManager* MTPFileSystemBackendDelegate::GetWatcherManager(
const storage::FileSystemURL& url) {
NOTIMPLEMENTED();
return NULL;
}
} // namespace chromeos } // namespace chromeos
...@@ -12,6 +12,15 @@ namespace base { ...@@ -12,6 +12,15 @@ namespace base {
class FilePath; class FilePath;
} // namespace base } // namespace base
namespace storage {
class AsyncFileUtil;
class FileSystemContext;
class FileStreamReader;
class FileSystemURL;
class FileStreamWriter;
class WatcherManager;
} // namespace storage
class DeviceMediaAsyncFileUtil; class DeviceMediaAsyncFileUtil;
namespace chromeos { namespace chromeos {
...@@ -36,6 +45,8 @@ class MTPFileSystemBackendDelegate : public FileSystemBackendDelegate { ...@@ -36,6 +45,8 @@ class MTPFileSystemBackendDelegate : public FileSystemBackendDelegate {
const storage::FileSystemURL& url, const storage::FileSystemURL& url,
int64 offset, int64 offset,
storage::FileSystemContext* context) OVERRIDE; storage::FileSystemContext* context) OVERRIDE;
virtual storage::WatcherManager* GetWatcherManager(
const storage::FileSystemURL& url) OVERRIDE;
private: private:
scoped_ptr<DeviceMediaAsyncFileUtil> device_media_async_file_util_; scoped_ptr<DeviceMediaAsyncFileUtil> device_media_async_file_util_;
......
benwells@chromium.org benwells@chromium.org
mtomasz@chromium.org
sammc@chromium.org sammc@chromium.org
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/extensions/api/file_system/entry_watcher_service.h"
#include "base/thread_task_runner_handle.h"
#include "chrome/browser/extensions/extension_util.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/common/extensions/api/file_system.h"
#include "components/keyed_service/content/browser_context_dependency_manager.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/storage_partition.h"
#include "extensions/browser/event_router.h"
#include "webkit/browser/fileapi/file_system_context.h"
namespace extensions {
namespace {
// Default implementation for dispatching an event. Can be replaced for unit
// tests by EntryWatcherService::SetDispatchEventImplForTesting().
void DispatchEventImpl(EventRouter* event_router,
const std::string& extension_id,
scoped_ptr<Event> event) {
event_router->DispatchEventToExtension(extension_id, event.Pass());
}
// Default implementation for acquiring a file system context for a specific
// |extension_id| and |context|.
storage::FileSystemContext* GetFileSystemContextImpl(
const std::string& extension_id,
content::BrowserContext* context) {
const GURL site = util::GetSiteForExtensionId(extension_id, context);
return content::BrowserContext::GetStoragePartitionForSite(context, site)
->GetFileSystemContext();
}
} // namespace
EntryWatcherService::EntryWatcherService(content::BrowserContext* context)
: context_(context),
dispatch_event_impl_(
base::Bind(&DispatchEventImpl, EventRouter::Get(context))),
get_file_system_context_impl_(base::Bind(&GetFileSystemContextImpl)),
observing_(this),
weak_ptr_factory_(this) {
// TODO(mtomasz): Restore persistent watchers.
}
EntryWatcherService::~EntryWatcherService() {
}
void EntryWatcherService::SetDispatchEventImplForTesting(
const DispatchEventImplCallback& callback) {
dispatch_event_impl_ = callback;
}
void EntryWatcherService::SetGetFileSystemContextImplForTesting(
const GetFileSystemContextImplCallback& callback) {
get_file_system_context_impl_ = callback;
}
void EntryWatcherService::WatchDirectory(
const std::string& extension_id,
const storage::FileSystemURL& url,
bool recursive,
const storage::WatcherManager::StatusCallback& callback) {
// TODO(mtomasz): Add support for recursive watchers.
if (recursive) {
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
base::Bind(callback, base::File::FILE_ERROR_INVALID_OPERATION));
return;
}
storage::FileSystemContext* const context =
get_file_system_context_impl_.Run(extension_id, context_);
DCHECK(context);
storage::WatcherManager* const watcher_manager =
context->GetWatcherManager(url.type());
if (!watcher_manager) {
// Post a task instead of calling the callback directly, since the caller
// may expect the callback to be called asynchronously.
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
base::Bind(callback, base::File::FILE_ERROR_INVALID_OPERATION));
return;
}
// Passing a pointer to WatcherManager is safe, since the pointer is required
// to be valid until shutdown.
context->default_file_task_runner()->PostNonNestableTask(
FROM_HERE,
base::Bind(&storage::WatcherManager::WatchDirectory,
base::Unretained(watcher_manager), // Outlives the service.
url,
recursive,
base::Bind(&EntryWatcherService::OnWatchDirectoryCompleted,
weak_ptr_factory_.GetWeakPtr(),
watcher_manager, // Outlives the service.
extension_id,
url,
recursive,
callback)));
}
void EntryWatcherService::UnwatchEntry(
const std::string& extension_id,
const storage::FileSystemURL& url,
const storage::WatcherManager::StatusCallback& callback) {
storage::FileSystemContext* const context =
get_file_system_context_impl_.Run(extension_id, context_);
DCHECK(context);
storage::WatcherManager* const watcher_manager =
context->GetWatcherManager(url.type());
if (!watcher_manager) {
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
base::Bind(callback, base::File::FILE_ERROR_INVALID_OPERATION));
return;
}
// Passing a pointer to WatcherManager is safe, since the pointer is required
// to be valid until shutdown.
context->default_file_task_runner()->PostNonNestableTask(
FROM_HERE,
base::Bind(&storage::WatcherManager::UnwatchEntry,
base::Unretained(watcher_manager), // Outlives the service.
url,
base::Bind(&EntryWatcherService::OnUnwatchEntryCompleted,
weak_ptr_factory_.GetWeakPtr(),
extension_id,
url,
callback)));
}
std::vector<storage::FileSystemURL> EntryWatcherService::GetWatchedEntries(
const std::string& extension_id) {
std::vector<storage::FileSystemURL> result;
for (WatcherMap::const_iterator it = watchers_.begin(); it != watchers_.end();
++it) {
const std::map<std::string, EntryWatcher>::const_iterator watcher_it =
it->second.find(extension_id);
if (watcher_it != it->second.end())
result.push_back(watcher_it->second.url);
}
return result;
}
void EntryWatcherService::OnEntryChanged(const storage::FileSystemURL& url) {
const WatcherMap::const_iterator it = watchers_.find(url);
DCHECK(it != watchers_.end());
for (std::map<std::string, EntryWatcher>::const_iterator watcher_it =
it->second.begin();
watcher_it != it->second.end();
++watcher_it) {
const std::string& extension_id = watcher_it->first;
api::file_system::EntryChangedEvent event;
dispatch_event_impl_.Run(
extension_id,
make_scoped_ptr(
new Event(api::file_system::OnEntryChanged::kEventName,
api::file_system::OnEntryChanged::Create(event))));
}
}
void EntryWatcherService::OnEntryRemoved(const storage::FileSystemURL& url) {
WatcherMap::const_iterator it = watchers_.find(url);
DCHECK(it != watchers_.end());
for (std::map<std::string, EntryWatcher>::const_iterator watcher_it =
it->second.begin();
watcher_it != it->second.end();
++watcher_it) {
const std::string& extension_id = watcher_it->first;
api::file_system::EntryRemovedEvent event;
dispatch_event_impl_.Run(
extension_id,
make_scoped_ptr(
new Event(api::file_system::OnEntryRemoved::kEventName,
api::file_system::OnEntryRemoved::Create(event))));
}
}
void EntryWatcherService::OnWatchDirectoryCompleted(
storage::WatcherManager* watcher_manager,
const std::string& extension_id,
const storage::FileSystemURL& url,
bool recursive,
const storage::WatcherManager::StatusCallback& callback,
base::File::Error result) {
if (result != base::File::FILE_OK) {
callback.Run(result);
return;
}
storage::FileSystemContext* const context =
get_file_system_context_impl_.Run(extension_id, context_);
DCHECK(context);
// Observe the manager if not observed yet.
if (!observing_.IsObserving(watcher_manager))
observing_.Add(watcher_manager);
watchers_[url][extension_id] =
EntryWatcher(url, true /* directory */, recursive);
// TODO(mtomasz): Save in preferences.
callback.Run(base::File::FILE_OK);
}
void EntryWatcherService::OnUnwatchEntryCompleted(
const std::string& extension_id,
const storage::FileSystemURL& url,
const storage::WatcherManager::StatusCallback& callback,
base::File::Error result) {
if (result != base::File::FILE_OK) {
callback.Run(result);
return;
}
if (watchers_[url].erase(extension_id) == 0) {
callback.Run(base::File::FILE_ERROR_NOT_FOUND);
return;
}
if (watchers_[url].empty())
watchers_.erase(url);
// TODO(mtomasz): Save in preferences.
callback.Run(base::File::FILE_OK);
}
EntryWatcherService::EntryWatcher::EntryWatcher()
: directory(false), recursive(false) {
}
EntryWatcherService::EntryWatcher::EntryWatcher(
const storage::FileSystemURL& url,
bool directory,
bool recursive)
: url(url), directory(directory), recursive(recursive) {
}
EntryWatcherService::EntryWatcher::~EntryWatcher() {
}
} // namespace extensions
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_EXTENSIONS_API_FILE_SYSTEM_ENTRY_WATCHER_SERVICE_H_
#define CHROME_BROWSER_EXTENSIONS_API_FILE_SYSTEM_ENTRY_WATCHER_SERVICE_H_
#include <map>
#include <string>
#include <vector>
#include "base/memory/singleton.h"
#include "base/memory/weak_ptr.h"
#include "base/scoped_observer.h"
#include "components/keyed_service/content/browser_context_keyed_service_factory.h"
#include "components/keyed_service/core/keyed_service.h"
#include "webkit/browser/fileapi/file_system_url.h"
#include "webkit/browser/fileapi/watcher_manager.h"
namespace content {
class BrowserContext;
} // namespace content
namespace storage {
class FileSystemContext;
} // namespace storage
namespace extensions {
struct Event;
class EventRouter;
// Watches entries (files and directories) for changes. Created per profile.
// TODO(mtomasz): Add support for watching files.
class EntryWatcherService : public KeyedService,
public storage::WatcherManager::Observer {
public:
typedef base::Callback<
void(const std::string& extension_id, scoped_ptr<Event> event)>
DispatchEventImplCallback;
typedef base::Callback<storage::FileSystemContext*(
const std::string& extension_id,
content::BrowserContext* context)> GetFileSystemContextImplCallback;
explicit EntryWatcherService(content::BrowserContext* context);
virtual ~EntryWatcherService();
// Watches a directory. Only one watcher can be set per the same |url| and
// |extension_id|.
void WatchDirectory(const std::string& extension_id,
const storage::FileSystemURL& url,
bool recursive,
const storage::WatcherManager::StatusCallback& callback);
// Unwatches an entry (file or directory).
void UnwatchEntry(const std::string& extension_id,
const storage::FileSystemURL& url,
const storage::WatcherManager::StatusCallback& callback);
std::vector<storage::FileSystemURL> GetWatchedEntries(
const std::string& extension_id);
// storage::WatcherManager::Observer overrides.
virtual void OnEntryChanged(const storage::FileSystemURL& url) OVERRIDE;
virtual void OnEntryRemoved(const storage::FileSystemURL& url) OVERRIDE;
// Sets a custom dispatcher for tests in order to be able to verify dispatched
// events.
void SetDispatchEventImplForTesting(
const DispatchEventImplCallback& callback);
// Sets a custom context getter for tests in order to inject a testing
// file system context implementation.
void SetGetFileSystemContextImplForTesting(
const GetFileSystemContextImplCallback& callback);
private:
// Holds information about an active entry watcher.
struct EntryWatcher {
EntryWatcher();
EntryWatcher(const storage::FileSystemURL& url,
bool directory,
bool recursive);
~EntryWatcher();
storage::FileSystemURL url;
bool directory;
bool recursive;
};
// Map from a file system url to a map from an extension id to an entry
// watcher descriptor.
typedef std::map<storage::FileSystemURL,
std::map<std::string, EntryWatcher>,
storage::FileSystemURL::Comparator> WatcherMap;
// Called when adding a directory watcher is completed with either a success
// or an error.
void OnWatchDirectoryCompleted(
storage::WatcherManager* watcher_manager,
const std::string& extension_id,
const storage::FileSystemURL& url,
bool recursive,
const storage::WatcherManager::StatusCallback& callback,
base::File::Error result);
// Called when removing a watcher is completed with either a success or an
// error.
void OnUnwatchEntryCompleted(
const std::string& extension_id,
const storage::FileSystemURL& url,
const storage::WatcherManager::StatusCallback& callback,
base::File::Error result);
content::BrowserContext* context_;
WatcherMap watchers_;
DispatchEventImplCallback dispatch_event_impl_;
GetFileSystemContextImplCallback get_file_system_context_impl_;
ScopedObserver<storage::WatcherManager, storage::WatcherManager::Observer>
observing_;
base::WeakPtrFactory<EntryWatcherService> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(EntryWatcherService);
};
} // namespace extensions
#endif // CHROME_BROWSER_EXTENSIONS_API_FILE_SYSTEM_ENTRY_WATCHER_SERVICE_H_
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/extensions/api/file_system/entry_watcher_service_factory.h"
#include "chrome/browser/extensions/api/file_system/entry_watcher_service.h"
#include "chrome/browser/profiles/profile.h"
#include "components/keyed_service/content/browser_context_dependency_manager.h"
#include "content/public/browser/browser_context.h"
namespace extensions {
EntryWatcherServiceFactory* EntryWatcherServiceFactory::GetInstance() {
return Singleton<EntryWatcherServiceFactory>::get();
}
EntryWatcherServiceFactory::EntryWatcherServiceFactory()
: BrowserContextKeyedServiceFactory(
"EntryWatcherService",
BrowserContextDependencyManager::GetInstance()) {
}
EntryWatcherServiceFactory::~EntryWatcherServiceFactory() {
}
KeyedService* EntryWatcherServiceFactory::BuildServiceInstanceFor(
content::BrowserContext* context) const {
return new EntryWatcherService(Profile::FromBrowserContext(context));
}
bool EntryWatcherServiceFactory::ServiceIsCreatedWithBrowserContext() const {
// Required to restore persistent watchers as soon as the profile is loaded.
return true;
}
} // namespace extensions
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_EXTENSIONS_API_FILE_SYSTEM_ENTRY_WATCHER_SERVICE_FACTORY_H_
#define CHROME_BROWSER_EXTENSIONS_API_FILE_SYSTEM_ENTRY_WATCHER_SERVICE_FACTORY_H_
#include "base/memory/singleton.h"
#include "components/keyed_service/content/browser_context_keyed_service_factory.h"
namespace content {
class BrowserContext;
} // namespace content
namespace extensions {
class EntryWatcherService;
// Creates instances of the EntryWatcherService class.
class EntryWatcherServiceFactory : public BrowserContextKeyedServiceFactory {
public:
// Returns a service instance singleton per |context|, after creating it
// (if necessary).
static EntryWatcherService* Get(content::BrowserContext* context);
// Returns a service instance for the context if exists. Otherwise, returns
// NULL.
static EntryWatcherService* FindExisting(content::BrowserContext* context);
// Gets a singleton instance of the factory.
static EntryWatcherServiceFactory* GetInstance();
private:
friend struct DefaultSingletonTraits<EntryWatcherServiceFactory>;
EntryWatcherServiceFactory();
virtual ~EntryWatcherServiceFactory();
// BrowserContextKeyedServiceFactory overrides:
virtual KeyedService* BuildServiceInstanceFor(
content::BrowserContext* profile) const OVERRIDE;
virtual bool ServiceIsCreatedWithBrowserContext() const OVERRIDE;
DISALLOW_COPY_AND_ASSIGN(EntryWatcherServiceFactory);
};
} // namespace extensions
#endif // CHROME_BROWSER_EXTENSIONS_API_FILE_SYSTEM_ENTRY_WATCHER_SERVICE_FACTORY_H_
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/extensions/api/file_system/entry_watcher_service.h"
#include <string>
#include <vector>
#include "base/files/file.h"
#include "base/files/file_path.h"
#include "base/files/scoped_temp_dir.h"
#include "base/memory/scoped_vector.h"
#include "base/run_loop.h"
#include "chrome/common/extensions/api/file_system.h"
#include "chrome/test/base/testing_profile.h"
#include "content/public/test/test_browser_thread_bundle.h"
#include "content/public/test/test_file_system_context.h"
#include "extensions/browser/event_router.h"
#include "webkit/browser/fileapi/file_system_url.h"
#include "webkit/common/fileapi/file_system_types.h"
namespace extensions {
namespace {
const char kExtensionId[] = "mbflcebpggnecokmikipoihdbecnjfoj";
void LogStatus(std::vector<base::File::Error>* log, base::File::Error status) {
log->push_back(status);
}
} // namespace
class EntryWatcherServiceTest : public testing::Test {
protected:
EntryWatcherServiceTest() {}
virtual ~EntryWatcherServiceTest() {}
virtual void SetUp() OVERRIDE {
profile_.reset(new TestingProfile);
ASSERT_TRUE(data_dir_.CreateUniqueTempDir());
file_system_context_ =
content::CreateFileSystemContextForTesting(NULL, data_dir_.path());
service_.reset(new EntryWatcherService(profile_.get()));
service_->SetDispatchEventImplForTesting(base::Bind(
&EntryWatcherServiceTest::DispatchEventImpl, base::Unretained(this)));
service_->SetGetFileSystemContextImplForTesting(
base::Bind(&EntryWatcherServiceTest::GetFileSystemContextImpl,
base::Unretained(this)));
testing_url_ = file_system_context_->CreateCrackedFileSystemURL(
GURL(std::string("chrome-extension://") + kExtensionId),
storage::kFileSystemTypeTest,
base::FilePath::FromUTF8Unsafe("/x/y/z"));
}
virtual void TearDown() OVERRIDE {
dispatch_event_log_targets_.clear();
dispatch_event_log_events_.clear();
}
void DispatchEventImpl(const std::string& extension_id,
scoped_ptr<Event> event) {
dispatch_event_log_targets_.push_back(extension_id);
dispatch_event_log_events_.push_back(event.release());
}
storage::FileSystemContext* GetFileSystemContextImpl(
const std::string& extension_id,
content::BrowserContext* context) {
EXPECT_EQ(kExtensionId, extension_id);
EXPECT_EQ(profile_.get(), context);
return file_system_context_.get();
}
content::TestBrowserThreadBundle thread_bundle_;
scoped_ptr<TestingProfile> profile_;
base::ScopedTempDir data_dir_;
scoped_refptr<storage::FileSystemContext> file_system_context_;
scoped_ptr<EntryWatcherService> service_;
storage::FileSystemURL testing_url_;
std::vector<std::string> dispatch_event_log_targets_;
ScopedVector<Event> dispatch_event_log_events_;
};
TEST_F(EntryWatcherServiceTest, GetWatchedEntries) {
std::vector<base::File::Error> log;
const bool recursive = false;
service_->WatchDirectory(
kExtensionId, testing_url_, recursive, base::Bind(&LogStatus, &log));
base::RunLoop().RunUntilIdle();
ASSERT_EQ(1u, log.size());
EXPECT_EQ(base::File::FILE_OK, log[0]);
{
const std::vector<storage::FileSystemURL> watched_entries =
service_->GetWatchedEntries(kExtensionId);
ASSERT_EQ(1u, watched_entries.size());
EXPECT_EQ(testing_url_, watched_entries[0]);
}
{
const std::string wrong_extension_id = "abcabcabcabcabcabcabcabcabcabcab";
const std::vector<storage::FileSystemURL> watched_entries =
service_->GetWatchedEntries(wrong_extension_id);
EXPECT_EQ(0u, watched_entries.size());
}
}
TEST_F(EntryWatcherServiceTest, WatchDirectory) {
std::vector<base::File::Error> log;
const bool recursive = false;
service_->WatchDirectory(
kExtensionId, testing_url_, recursive, base::Bind(&LogStatus, &log));
base::RunLoop().RunUntilIdle();
ASSERT_EQ(1u, log.size());
EXPECT_EQ(base::File::FILE_OK, log[0]);
// The testing WatcherManager implementation emits two hard-coded fake
// notifications as soon as the watcher is set properly. See:
// TestWatcherManager::WatchDirectory() for details.
ASSERT_LE(1u, dispatch_event_log_targets_.size());
ASSERT_LE(1u, dispatch_event_log_events_.size());
EXPECT_EQ(kExtensionId, dispatch_event_log_targets_[0]);
EXPECT_EQ(api::file_system::OnEntryChanged::kEventName,
dispatch_event_log_events_[0]->event_name);
ASSERT_LE(2u, dispatch_event_log_targets_.size());
ASSERT_LE(2u, dispatch_event_log_events_.size());
EXPECT_EQ(kExtensionId, dispatch_event_log_targets_[1]);
EXPECT_EQ(api::file_system::OnEntryRemoved::kEventName,
dispatch_event_log_events_[1]->event_name);
// No unexpected events.
ASSERT_EQ(2u, dispatch_event_log_targets_.size());
ASSERT_EQ(2u, dispatch_event_log_events_.size());
const std::vector<storage::FileSystemURL> watched_entries =
service_->GetWatchedEntries(kExtensionId);
ASSERT_EQ(1u, watched_entries.size());
EXPECT_EQ(testing_url_, watched_entries[0]);
}
TEST_F(EntryWatcherServiceTest, WatchDirectory_AlreadyExists) {
std::vector<base::File::Error> log;
const bool recursive = false;
service_->WatchDirectory(
kExtensionId, testing_url_, recursive, base::Bind(&LogStatus, &log));
base::RunLoop().RunUntilIdle();
ASSERT_EQ(1u, log.size());
EXPECT_EQ(base::File::FILE_OK, log[0]);
ASSERT_EQ(2u, dispatch_event_log_targets_.size());
ASSERT_EQ(2u, dispatch_event_log_events_.size());
{
const std::vector<storage::FileSystemURL> watched_entries =
service_->GetWatchedEntries(kExtensionId);
EXPECT_EQ(1u, watched_entries.size());
}
service_->WatchDirectory(
kExtensionId, testing_url_, recursive, base::Bind(&LogStatus, &log));
base::RunLoop().RunUntilIdle();
ASSERT_EQ(2u, log.size());
EXPECT_EQ(base::File::FILE_ERROR_EXISTS, log[1]);
// No new unexpected events.
ASSERT_EQ(2u, dispatch_event_log_targets_.size());
ASSERT_EQ(2u, dispatch_event_log_events_.size());
{
const std::vector<storage::FileSystemURL> watched_entries =
service_->GetWatchedEntries(kExtensionId);
EXPECT_EQ(1u, watched_entries.size());
}
}
TEST_F(EntryWatcherServiceTest, WatchDirectory_Recursive) {
std::vector<base::File::Error> log;
const bool recursive = true;
service_->WatchDirectory(
kExtensionId, testing_url_, recursive, base::Bind(&LogStatus, &log));
base::RunLoop().RunUntilIdle();
// Recursive watchers are not supported yet.
ASSERT_EQ(1u, log.size());
EXPECT_EQ(base::File::FILE_ERROR_INVALID_OPERATION, log[0]);
// No unexpected events.
ASSERT_EQ(0u, dispatch_event_log_targets_.size());
ASSERT_EQ(0u, dispatch_event_log_events_.size());
const std::vector<storage::FileSystemURL> watched_entries =
service_->GetWatchedEntries(kExtensionId);
EXPECT_EQ(0u, watched_entries.size());
}
TEST_F(EntryWatcherServiceTest, UnwatchEntry) {
std::vector<base::File::Error> watch_log;
const bool recursive = false;
service_->WatchDirectory(kExtensionId,
testing_url_,
recursive,
base::Bind(&LogStatus, &watch_log));
base::RunLoop().RunUntilIdle();
ASSERT_EQ(1u, watch_log.size());
EXPECT_EQ(base::File::FILE_OK, watch_log[0]);
ASSERT_EQ(2u, dispatch_event_log_targets_.size());
ASSERT_EQ(2u, dispatch_event_log_events_.size());
{
const std::vector<storage::FileSystemURL> watched_entries =
service_->GetWatchedEntries(kExtensionId);
EXPECT_EQ(1u, watched_entries.size());
}
std::vector<base::File::Error> unwatch_log;
service_->UnwatchEntry(
kExtensionId, testing_url_, base::Bind(&LogStatus, &unwatch_log));
base::RunLoop().RunUntilIdle();
ASSERT_EQ(1u, unwatch_log.size());
EXPECT_EQ(base::File::FILE_OK, unwatch_log[0]);
{
const std::vector<storage::FileSystemURL> watched_entries =
service_->GetWatchedEntries(kExtensionId);
EXPECT_EQ(0u, watched_entries.size());
}
}
TEST_F(EntryWatcherServiceTest, UnwatchEntry_NotFound) {
std::vector<base::File::Error> log;
service_->UnwatchEntry(
kExtensionId, testing_url_, base::Bind(&LogStatus, &log));
base::RunLoop().RunUntilIdle();
ASSERT_EQ(1u, log.size());
EXPECT_EQ(base::File::FILE_ERROR_NOT_FOUND, log[0]);
}
} // namespace extensions
...@@ -4,6 +4,8 @@ ...@@ -4,6 +4,8 @@
#include "chrome/browser/extensions/api/file_system/file_system_api.h" #include "chrome/browser/extensions/api/file_system/file_system_api.h"
#include <set>
#include "apps/app_window.h" #include "apps/app_window.h"
#include "apps/app_window_registry.h" #include "apps/app_window_registry.h"
#include "apps/saved_files_service.h" #include "apps/saved_files_service.h"
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
#ifndef CHROME_BROWSER_EXTENSIONS_API_FILE_SYSTEM_FILE_SYSTEM_API_H_ #ifndef CHROME_BROWSER_EXTENSIONS_API_FILE_SYSTEM_FILE_SYSTEM_API_H_
#define CHROME_BROWSER_EXTENSIONS_API_FILE_SYSTEM_FILE_SYSTEM_API_H_ #define CHROME_BROWSER_EXTENSIONS_API_FILE_SYSTEM_FILE_SYSTEM_API_H_
#include <string>
#include <vector> #include <vector>
#include "base/files/file_path.h" #include "base/files/file_path.h"
......
...@@ -55,6 +55,11 @@ storage::AsyncFileUtil* PrivetFileSystemBackend::GetAsyncFileUtil( ...@@ -55,6 +55,11 @@ storage::AsyncFileUtil* PrivetFileSystemBackend::GetAsyncFileUtil(
return async_util_.get(); return async_util_.get();
} }
storage::WatcherManager* PrivetFileSystemBackend::GetWatcherManager(
storage::FileSystemType type) {
return NULL;
}
storage::CopyOrMoveFileValidatorFactory* storage::CopyOrMoveFileValidatorFactory*
PrivetFileSystemBackend::GetCopyOrMoveFileValidatorFactory( PrivetFileSystemBackend::GetCopyOrMoveFileValidatorFactory(
storage::FileSystemType type, storage::FileSystemType type,
......
...@@ -35,6 +35,8 @@ class PrivetFileSystemBackend : public storage::FileSystemBackend { ...@@ -35,6 +35,8 @@ class PrivetFileSystemBackend : public storage::FileSystemBackend {
virtual storage::AsyncFileUtil* GetAsyncFileUtil( virtual storage::AsyncFileUtil* GetAsyncFileUtil(
storage::FileSystemType type) OVERRIDE; storage::FileSystemType type) OVERRIDE;
virtual storage::WatcherManager* GetWatcherManager(
storage::FileSystemType type) OVERRIDE;
virtual storage::CopyOrMoveFileValidatorFactory* virtual storage::CopyOrMoveFileValidatorFactory*
GetCopyOrMoveFileValidatorFactory(storage::FileSystemType type, GetCopyOrMoveFileValidatorFactory(storage::FileSystemType type,
base::File::Error* error_code) OVERRIDE; base::File::Error* error_code) OVERRIDE;
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
#include "chrome/browser/media_galleries/fileapi/media_file_system_backend.h" #include "chrome/browser/media_galleries/fileapi/media_file_system_backend.h"
#include <string> #include <string>
#include <vector>
#include "base/bind.h" #include "base/bind.h"
#include "base/files/file_path.h" #include "base/files/file_path.h"
...@@ -269,6 +270,11 @@ storage::AsyncFileUtil* MediaFileSystemBackend::GetAsyncFileUtil( ...@@ -269,6 +270,11 @@ storage::AsyncFileUtil* MediaFileSystemBackend::GetAsyncFileUtil(
return NULL; return NULL;
} }
storage::WatcherManager* MediaFileSystemBackend::GetWatcherManager(
storage::FileSystemType type) {
return NULL;
}
storage::CopyOrMoveFileValidatorFactory* storage::CopyOrMoveFileValidatorFactory*
MediaFileSystemBackend::GetCopyOrMoveFileValidatorFactory( MediaFileSystemBackend::GetCopyOrMoveFileValidatorFactory(
storage::FileSystemType type, storage::FileSystemType type,
......
...@@ -61,6 +61,8 @@ class MediaFileSystemBackend : public storage::FileSystemBackend { ...@@ -61,6 +61,8 @@ class MediaFileSystemBackend : public storage::FileSystemBackend {
const OpenFileSystemCallback& callback) OVERRIDE; const OpenFileSystemCallback& callback) OVERRIDE;
virtual storage::AsyncFileUtil* GetAsyncFileUtil( virtual storage::AsyncFileUtil* GetAsyncFileUtil(
storage::FileSystemType type) OVERRIDE; storage::FileSystemType type) OVERRIDE;
virtual storage::WatcherManager* GetWatcherManager(
storage::FileSystemType type) OVERRIDE;
virtual storage::CopyOrMoveFileValidatorFactory* virtual storage::CopyOrMoveFileValidatorFactory*
GetCopyOrMoveFileValidatorFactory(storage::FileSystemType type, GetCopyOrMoveFileValidatorFactory(storage::FileSystemType type,
base::File::Error* error_code) OVERRIDE; base::File::Error* error_code) OVERRIDE;
......
...@@ -4,6 +4,8 @@ ...@@ -4,6 +4,8 @@
#include "chrome/browser/sync_file_system/local/sync_file_system_backend.h" #include "chrome/browser/sync_file_system/local/sync_file_system_backend.h"
#include <string>
#include "base/logging.h" #include "base/logging.h"
#include "chrome/browser/chrome_notification_types.h" #include "chrome/browser/chrome_notification_types.h"
#include "chrome/browser/sync_file_system/local/local_file_change_tracker.h" #include "chrome/browser/sync_file_system/local/local_file_change_tracker.h"
...@@ -138,6 +140,11 @@ storage::AsyncFileUtil* SyncFileSystemBackend::GetAsyncFileUtil( ...@@ -138,6 +140,11 @@ storage::AsyncFileUtil* SyncFileSystemBackend::GetAsyncFileUtil(
return GetDelegate()->file_util(); return GetDelegate()->file_util();
} }
storage::WatcherManager* SyncFileSystemBackend::GetWatcherManager(
storage::FileSystemType type) {
return NULL;
}
storage::CopyOrMoveFileValidatorFactory* storage::CopyOrMoveFileValidatorFactory*
SyncFileSystemBackend::GetCopyOrMoveFileValidatorFactory( SyncFileSystemBackend::GetCopyOrMoveFileValidatorFactory(
storage::FileSystemType type, storage::FileSystemType type,
......
...@@ -34,6 +34,8 @@ class SyncFileSystemBackend : public storage::FileSystemBackend { ...@@ -34,6 +34,8 @@ class SyncFileSystemBackend : public storage::FileSystemBackend {
const OpenFileSystemCallback& callback) OVERRIDE; const OpenFileSystemCallback& callback) OVERRIDE;
virtual storage::AsyncFileUtil* GetAsyncFileUtil( virtual storage::AsyncFileUtil* GetAsyncFileUtil(
storage::FileSystemType type) OVERRIDE; storage::FileSystemType type) OVERRIDE;
virtual storage::WatcherManager* GetWatcherManager(
storage::FileSystemType type) OVERRIDE;
virtual storage::CopyOrMoveFileValidatorFactory* virtual storage::CopyOrMoveFileValidatorFactory*
GetCopyOrMoveFileValidatorFactory(storage::FileSystemType type, GetCopyOrMoveFileValidatorFactory(storage::FileSystemType type,
base::File::Error* error_code) OVERRIDE; base::File::Error* error_code) OVERRIDE;
......
...@@ -283,6 +283,10 @@ ...@@ -283,6 +283,10 @@
'browser/extensions/api/file_handlers/app_file_handler_util.h', 'browser/extensions/api/file_handlers/app_file_handler_util.h',
'browser/extensions/api/file_handlers/mime_util.cc', 'browser/extensions/api/file_handlers/mime_util.cc',
'browser/extensions/api/file_handlers/mime_util.h', 'browser/extensions/api/file_handlers/mime_util.h',
'browser/extensions/api/file_system/entry_watcher_service.cc',
'browser/extensions/api/file_system/entry_watcher_service.h',
'browser/extensions/api/file_system/entry_watcher_service_factory.cc',
'browser/extensions/api/file_system/entry_watcher_service_factory.h',
'browser/extensions/api/file_system/file_system_api.cc', 'browser/extensions/api/file_system/file_system_api.cc',
'browser/extensions/api/file_system/file_system_api.h', 'browser/extensions/api/file_system/file_system_api.h',
'browser/extensions/api/font_settings/font_settings_api.cc', 'browser/extensions/api/font_settings/font_settings_api.cc',
......
...@@ -868,6 +868,7 @@ ...@@ -868,6 +868,7 @@
'browser/extensions/api/experience_sampling_private/experience_sampling_private_api_unittest.cc', 'browser/extensions/api/experience_sampling_private/experience_sampling_private_api_unittest.cc',
'browser/extensions/api/extension_action/extension_action_prefs_unittest.cc', 'browser/extensions/api/extension_action/extension_action_prefs_unittest.cc',
'browser/extensions/api/file_handlers/mime_util_unittest.cc', 'browser/extensions/api/file_handlers/mime_util_unittest.cc',
'browser/extensions/api/file_system/entry_watcher_service_unittest.cc',
'browser/extensions/api/file_system/file_system_api_unittest.cc', 'browser/extensions/api/file_system/file_system_api_unittest.cc',
'browser/extensions/api/identity/extension_token_key_unittest.cc', 'browser/extensions/api/identity/extension_token_key_unittest.cc',
'browser/extensions/api/identity/gaia_web_auth_flow_unittest.cc', 'browser/extensions/api/identity/gaia_web_auth_flow_unittest.cc',
......
...@@ -9,7 +9,11 @@ ...@@ -9,7 +9,11 @@
#include <vector> #include <vector>
#include "base/file_util.h" #include "base/file_util.h"
#include "base/files/file.h"
#include "base/memory/weak_ptr.h"
#include "base/observer_list.h"
#include "base/sequenced_task_runner.h" #include "base/sequenced_task_runner.h"
#include "base/thread_task_runner_handle.h"
#include "webkit/browser/blob/file_stream_reader.h" #include "webkit/browser/blob/file_stream_reader.h"
#include "webkit/browser/fileapi/copy_or_move_file_validator.h" #include "webkit/browser/fileapi/copy_or_move_file_validator.h"
#include "webkit/browser/fileapi/file_observers.h" #include "webkit/browser/fileapi/file_observers.h"
...@@ -20,6 +24,7 @@ ...@@ -20,6 +24,7 @@
#include "webkit/browser/fileapi/native_file_util.h" #include "webkit/browser/fileapi/native_file_util.h"
#include "webkit/browser/fileapi/quota/quota_reservation.h" #include "webkit/browser/fileapi/quota/quota_reservation.h"
#include "webkit/browser/fileapi/sandbox_file_stream_writer.h" #include "webkit/browser/fileapi/sandbox_file_stream_writer.h"
#include "webkit/browser/fileapi/watcher_manager.h"
#include "webkit/browser/quota/quota_manager.h" #include "webkit/browser/quota/quota_manager.h"
#include "webkit/common/fileapi/file_system_util.h" #include "webkit/common/fileapi/file_system_util.h"
...@@ -32,6 +37,7 @@ namespace content { ...@@ -32,6 +37,7 @@ namespace content {
namespace { namespace {
// Stub implementation of storage::LocalFileUtil.
class TestFileUtil : public storage::LocalFileUtil { class TestFileUtil : public storage::LocalFileUtil {
public: public:
explicit TestFileUtil(const base::FilePath& base_path) explicit TestFileUtil(const base::FilePath& base_path)
...@@ -51,6 +57,101 @@ class TestFileUtil : public storage::LocalFileUtil { ...@@ -51,6 +57,101 @@ class TestFileUtil : public storage::LocalFileUtil {
base::FilePath base_path_; base::FilePath base_path_;
}; };
// Stub implementation of storage::WatcherManager. Emits a fake notification
// after a directory watcher is set successfully.
class TestWatcherManager : public storage::WatcherManager {
public:
TestWatcherManager() : weak_ptr_factory_(this) {}
virtual ~TestWatcherManager() {}
// storage::WatcherManager overrides.
virtual void AddObserver(Observer* observer) OVERRIDE {
observers_.AddObserver(observer);
}
virtual void RemoveObserver(Observer* observer) OVERRIDE {
observers_.RemoveObserver(observer);
}
virtual bool HasObserver(Observer* observer) const OVERRIDE {
return observers_.HasObserver(observer);
}
virtual void WatchDirectory(const storage::FileSystemURL& url,
bool recursive,
const StatusCallback& callback) OVERRIDE {
if (recursive) {
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
base::Bind(callback, base::File::FILE_ERROR_INVALID_OPERATION));
return;
}
const GURL gurl = url.ToGURL();
if (watched_urls_.find(gurl) != watched_urls_.end()) {
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::Bind(callback, base::File::FILE_ERROR_EXISTS));
return;
}
watched_urls_.insert(gurl);
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::Bind(callback, base::File::FILE_OK));
// Send a fake changed notification.
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
base::Bind(&TestWatcherManager::SendFakeChangeNotification,
weak_ptr_factory_.GetWeakPtr(),
url));
// Send a fake removed notification.
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
base::Bind(&TestWatcherManager::SendFakeRemoveNotification,
weak_ptr_factory_.GetWeakPtr(),
url));
}
virtual void UnwatchEntry(const storage::FileSystemURL& url,
const StatusCallback& callback) OVERRIDE {
const GURL gurl = url.ToGURL();
if (watched_urls_.find(gurl) == watched_urls_.end()) {
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::Bind(callback, base::File::FILE_ERROR_NOT_FOUND));
return;
}
watched_urls_.erase(gurl);
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::Bind(callback, base::File::FILE_OK));
}
private:
// Sends a fake notification to each observer about a changed entry
// represented by |url|, as long as it is still being watched.
void SendFakeChangeNotification(const storage::FileSystemURL& url) {
if (watched_urls_.find(url.ToGURL()) == watched_urls_.end())
return;
FOR_EACH_OBSERVER(Observer, observers_, OnEntryChanged(url));
}
// Sends a fake notification to each observer about a removed entry
// represented by |url|, as long as it is still being watched.
void SendFakeRemoveNotification(const storage::FileSystemURL& url) {
if (watched_urls_.find(url.ToGURL()) == watched_urls_.end())
return;
FOR_EACH_OBSERVER(Observer, observers_, OnEntryRemoved(url));
}
ObserverList<Observer> observers_;
std::set<GURL> watched_urls_;
base::WeakPtrFactory<TestWatcherManager> weak_ptr_factory_;
};
} // namespace } // namespace
// This only supports single origin. // This only supports single origin.
...@@ -162,6 +263,7 @@ TestFileSystemBackend::TestFileSystemBackend( ...@@ -162,6 +263,7 @@ TestFileSystemBackend::TestFileSystemBackend(
: base_path_(base_path), : base_path_(base_path),
file_util_( file_util_(
new storage::AsyncFileUtilAdapter(new TestFileUtil(base_path))), new storage::AsyncFileUtilAdapter(new TestFileUtil(base_path))),
watcher_manager_(new TestWatcherManager()),
quota_util_(new QuotaUtil(task_runner)), quota_util_(new QuotaUtil(task_runner)),
require_copy_or_move_validator_(false) { require_copy_or_move_validator_(false) {
} }
...@@ -189,6 +291,11 @@ storage::AsyncFileUtil* TestFileSystemBackend::GetAsyncFileUtil( ...@@ -189,6 +291,11 @@ storage::AsyncFileUtil* TestFileSystemBackend::GetAsyncFileUtil(
return file_util_.get(); return file_util_.get();
} }
storage::WatcherManager* TestFileSystemBackend::GetWatcherManager(
storage::FileSystemType type) {
return watcher_manager_.get();
}
storage::CopyOrMoveFileValidatorFactory* storage::CopyOrMoveFileValidatorFactory*
TestFileSystemBackend::GetCopyOrMoveFileValidatorFactory( TestFileSystemBackend::GetCopyOrMoveFileValidatorFactory(
storage::FileSystemType type, storage::FileSystemType type,
......
...@@ -41,6 +41,8 @@ class TestFileSystemBackend : public storage::FileSystemBackend { ...@@ -41,6 +41,8 @@ class TestFileSystemBackend : public storage::FileSystemBackend {
const OpenFileSystemCallback& callback) OVERRIDE; const OpenFileSystemCallback& callback) OVERRIDE;
virtual storage::AsyncFileUtil* GetAsyncFileUtil( virtual storage::AsyncFileUtil* GetAsyncFileUtil(
storage::FileSystemType type) OVERRIDE; storage::FileSystemType type) OVERRIDE;
virtual storage::WatcherManager* GetWatcherManager(
storage::FileSystemType type) OVERRIDE;
virtual storage::CopyOrMoveFileValidatorFactory* virtual storage::CopyOrMoveFileValidatorFactory*
GetCopyOrMoveFileValidatorFactory(storage::FileSystemType type, GetCopyOrMoveFileValidatorFactory(storage::FileSystemType type,
base::File::Error* error_code) OVERRIDE; base::File::Error* error_code) OVERRIDE;
...@@ -85,6 +87,7 @@ class TestFileSystemBackend : public storage::FileSystemBackend { ...@@ -85,6 +87,7 @@ class TestFileSystemBackend : public storage::FileSystemBackend {
base::FilePath base_path_; base::FilePath base_path_;
scoped_refptr<base::SequencedTaskRunner> task_runner_; scoped_refptr<base::SequencedTaskRunner> task_runner_;
scoped_ptr<storage::AsyncFileUtilAdapter> file_util_; scoped_ptr<storage::AsyncFileUtilAdapter> file_util_;
scoped_ptr<storage::WatcherManager> watcher_manager_;
scoped_ptr<QuotaUtil> quota_util_; scoped_ptr<QuotaUtil> quota_util_;
bool require_copy_or_move_validator_; bool require_copy_or_move_validator_;
......
...@@ -33,6 +33,7 @@ class FileSystemContext; ...@@ -33,6 +33,7 @@ class FileSystemContext;
class FileSystemFileUtil; class FileSystemFileUtil;
class FileSystemOperation; class FileSystemOperation;
class FileSystemQuotaUtil; class FileSystemQuotaUtil;
class WatcherManager;
// An interface for defining a file system backend. // An interface for defining a file system backend.
// //
...@@ -70,6 +71,9 @@ class STORAGE_EXPORT FileSystemBackend { ...@@ -70,6 +71,9 @@ class STORAGE_EXPORT FileSystemBackend {
// Returns the specialized AsyncFileUtil for this backend. // Returns the specialized AsyncFileUtil for this backend.
virtual AsyncFileUtil* GetAsyncFileUtil(FileSystemType type) = 0; virtual AsyncFileUtil* GetAsyncFileUtil(FileSystemType type) = 0;
// Returns the specialized WatcherManager for this backend.
virtual WatcherManager* GetWatcherManager(FileSystemType type) = 0;
// Returns the specialized CopyOrMoveFileValidatorFactory for this backend // Returns the specialized CopyOrMoveFileValidatorFactory for this backend
// and |type|. If |error_code| is File::FILE_OK and the result is NULL, // and |type|. If |error_code| is File::FILE_OK and the result is NULL,
// then no validator is required. // then no validator is required.
...@@ -105,6 +109,8 @@ class STORAGE_EXPORT FileSystemBackend { ...@@ -105,6 +109,8 @@ class STORAGE_EXPORT FileSystemBackend {
// ERR_UPLOAD_FILE_CHANGED error. // ERR_UPLOAD_FILE_CHANGED error.
// This method itself does *not* check if the given path exists and is a // This method itself does *not* check if the given path exists and is a
// regular file. // regular file.
// The |length| argument says how many bytes are going to be read using the
// instance of the file stream reader. If unknown, then equal to -1.
virtual scoped_ptr<storage::FileStreamReader> CreateFileStreamReader( virtual scoped_ptr<storage::FileStreamReader> CreateFileStreamReader(
const FileSystemURL& url, const FileSystemURL& url,
int64 offset, int64 offset,
......
...@@ -277,6 +277,14 @@ FileSystemBackend* FileSystemContext::GetFileSystemBackend( ...@@ -277,6 +277,14 @@ FileSystemBackend* FileSystemContext::GetFileSystemBackend(
return NULL; return NULL;
} }
WatcherManager* FileSystemContext::GetWatcherManager(
FileSystemType type) const {
FileSystemBackend* backend = GetFileSystemBackend(type);
if (!backend)
return NULL;
return backend->GetWatcherManager(type);
}
bool FileSystemContext::IsSandboxFileSystem(FileSystemType type) const { bool FileSystemContext::IsSandboxFileSystem(FileSystemType type) const {
FileSystemBackendMap::const_iterator found = backend_map_.find(type); FileSystemBackendMap::const_iterator found = backend_map_.find(type);
return found != backend_map_.end() && found->second->GetQuotaUtil(); return found != backend_map_.end() && found->second->GetQuotaUtil();
......
...@@ -65,6 +65,7 @@ class IsolatedFileSystemBackend; ...@@ -65,6 +65,7 @@ class IsolatedFileSystemBackend;
class MountPoints; class MountPoints;
class QuotaReservation; class QuotaReservation;
class SandboxFileSystemBackend; class SandboxFileSystemBackend;
class WatchManager;
struct DefaultContextDeleter; struct DefaultContextDeleter;
struct FileSystemInfo; struct FileSystemInfo;
...@@ -163,6 +164,10 @@ class STORAGE_EXPORT FileSystemContext ...@@ -163,6 +164,10 @@ class STORAGE_EXPORT FileSystemContext
FileSystemBackend* GetFileSystemBackend( FileSystemBackend* GetFileSystemBackend(
FileSystemType type) const; FileSystemType type) const;
// Returns the watcher manager for the given |type|.
// This may return NULL if the type does not support watching.
WatcherManager* GetWatcherManager(FileSystemType type) const;
// Returns true for sandboxed filesystems. Currently this does // Returns true for sandboxed filesystems. Currently this does
// the same as GetQuotaUtil(type) != NULL. (In an assumption that // the same as GetQuotaUtil(type) != NULL. (In an assumption that
// all sandboxed filesystems must cooperate with QuotaManager so that // all sandboxed filesystems must cooperate with QuotaManager so that
......
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
#include "webkit/browser/fileapi/isolated_context.h" #include "webkit/browser/fileapi/isolated_context.h"
#include "webkit/browser/fileapi/native_file_util.h" #include "webkit/browser/fileapi/native_file_util.h"
#include "webkit/browser/fileapi/transient_file_util.h" #include "webkit/browser/fileapi/transient_file_util.h"
#include "webkit/browser/fileapi/watcher_manager.h"
#include "webkit/common/fileapi/file_system_types.h" #include "webkit/common/fileapi/file_system_types.h"
#include "webkit/common/fileapi/file_system_util.h" #include "webkit/common/fileapi/file_system_util.h"
...@@ -84,6 +85,11 @@ AsyncFileUtil* IsolatedFileSystemBackend::GetAsyncFileUtil( ...@@ -84,6 +85,11 @@ AsyncFileUtil* IsolatedFileSystemBackend::GetAsyncFileUtil(
return NULL; return NULL;
} }
WatcherManager* IsolatedFileSystemBackend::GetWatcherManager(
FileSystemType type) {
return NULL;
}
CopyOrMoveFileValidatorFactory* CopyOrMoveFileValidatorFactory*
IsolatedFileSystemBackend::GetCopyOrMoveFileValidatorFactory( IsolatedFileSystemBackend::GetCopyOrMoveFileValidatorFactory(
FileSystemType type, base::File::Error* error_code) { FileSystemType type, base::File::Error* error_code) {
......
...@@ -24,6 +24,7 @@ class IsolatedFileSystemBackend : public FileSystemBackend { ...@@ -24,6 +24,7 @@ class IsolatedFileSystemBackend : public FileSystemBackend {
OpenFileSystemMode mode, OpenFileSystemMode mode,
const OpenFileSystemCallback& callback) OVERRIDE; const OpenFileSystemCallback& callback) OVERRIDE;
virtual AsyncFileUtil* GetAsyncFileUtil(FileSystemType type) OVERRIDE; virtual AsyncFileUtil* GetAsyncFileUtil(FileSystemType type) OVERRIDE;
virtual WatcherManager* GetWatcherManager(FileSystemType type) OVERRIDE;
virtual CopyOrMoveFileValidatorFactory* GetCopyOrMoveFileValidatorFactory( virtual CopyOrMoveFileValidatorFactory* GetCopyOrMoveFileValidatorFactory(
FileSystemType type, FileSystemType type,
base::File::Error* error_code) OVERRIDE; base::File::Error* error_code) OVERRIDE;
......
...@@ -160,6 +160,11 @@ PluginPrivateFileSystemBackend::GetAsyncFileUtil(FileSystemType type) { ...@@ -160,6 +160,11 @@ PluginPrivateFileSystemBackend::GetAsyncFileUtil(FileSystemType type) {
return file_util_.get(); return file_util_.get();
} }
WatcherManager* PluginPrivateFileSystemBackend::GetWatcherManager(
FileSystemType type) {
return NULL;
}
CopyOrMoveFileValidatorFactory* CopyOrMoveFileValidatorFactory*
PluginPrivateFileSystemBackend::GetCopyOrMoveFileValidatorFactory( PluginPrivateFileSystemBackend::GetCopyOrMoveFileValidatorFactory(
FileSystemType type, FileSystemType type,
......
...@@ -29,6 +29,7 @@ class SpecialStoragePolicy; ...@@ -29,6 +29,7 @@ class SpecialStoragePolicy;
namespace storage { namespace storage {
class ObfuscatedFileUtil; class ObfuscatedFileUtil;
class WatcherManager;
class STORAGE_EXPORT PluginPrivateFileSystemBackend class STORAGE_EXPORT PluginPrivateFileSystemBackend
: public FileSystemBackend, : public FileSystemBackend,
...@@ -65,6 +66,7 @@ class STORAGE_EXPORT PluginPrivateFileSystemBackend ...@@ -65,6 +66,7 @@ class STORAGE_EXPORT PluginPrivateFileSystemBackend
OpenFileSystemMode mode, OpenFileSystemMode mode,
const OpenFileSystemCallback& callback) OVERRIDE; const OpenFileSystemCallback& callback) OVERRIDE;
virtual AsyncFileUtil* GetAsyncFileUtil(FileSystemType type) OVERRIDE; virtual AsyncFileUtil* GetAsyncFileUtil(FileSystemType type) OVERRIDE;
virtual WatcherManager* GetWatcherManager(FileSystemType type) OVERRIDE;
virtual CopyOrMoveFileValidatorFactory* GetCopyOrMoveFileValidatorFactory( virtual CopyOrMoveFileValidatorFactory* GetCopyOrMoveFileValidatorFactory(
FileSystemType type, FileSystemType type,
base::File::Error* error_code) OVERRIDE; base::File::Error* error_code) OVERRIDE;
......
...@@ -85,6 +85,11 @@ AsyncFileUtil* SandboxFileSystemBackend::GetAsyncFileUtil( ...@@ -85,6 +85,11 @@ AsyncFileUtil* SandboxFileSystemBackend::GetAsyncFileUtil(
return delegate_->file_util(); return delegate_->file_util();
} }
WatcherManager* SandboxFileSystemBackend::GetWatcherManager(
FileSystemType type) {
return NULL;
}
CopyOrMoveFileValidatorFactory* CopyOrMoveFileValidatorFactory*
SandboxFileSystemBackend::GetCopyOrMoveFileValidatorFactory( SandboxFileSystemBackend::GetCopyOrMoveFileValidatorFactory(
FileSystemType type, FileSystemType type,
......
...@@ -38,6 +38,7 @@ class STORAGE_EXPORT SandboxFileSystemBackend ...@@ -38,6 +38,7 @@ class STORAGE_EXPORT SandboxFileSystemBackend
OpenFileSystemMode mode, OpenFileSystemMode mode,
const OpenFileSystemCallback& callback) OVERRIDE; const OpenFileSystemCallback& callback) OVERRIDE;
virtual AsyncFileUtil* GetAsyncFileUtil(FileSystemType type) OVERRIDE; virtual AsyncFileUtil* GetAsyncFileUtil(FileSystemType type) OVERRIDE;
virtual WatcherManager* GetWatcherManager(FileSystemType type) OVERRIDE;
virtual CopyOrMoveFileValidatorFactory* GetCopyOrMoveFileValidatorFactory( virtual CopyOrMoveFileValidatorFactory* GetCopyOrMoveFileValidatorFactory(
FileSystemType type, FileSystemType type,
base::File::Error* error_code) OVERRIDE; base::File::Error* error_code) OVERRIDE;
......
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef WEBKIT_BROWSER_FILEAPI_WATCHER_MANAGER_H_
#define WEBKIT_BROWSER_FILEAPI_WATCHER_MANAGER_H_
#include <vector>
#include "base/basictypes.h"
#include "base/callback_forward.h"
#include "base/files/file.h"
namespace base {
class Time;
}
namespace storage {
class FileSystemOperationContext;
class FileSystemURL;
// An interface for providing entry observing capability for file system
// backends.
//
// It is NOT valid to give null callback to this class, and implementors
// can assume that they don't get any null callbacks.
class WatcherManager {
public:
typedef base::Callback<void(base::File::Error result)> StatusCallback;
// Observes watched entries.
class Observer {
public:
Observer() {}
virtual ~Observer() {}
// Notifies about an entry represented by |url| being changed.
virtual void OnEntryChanged(const FileSystemURL& url) = 0;
// Notifies about an entry represented by |url| being removed.
virtual void OnEntryRemoved(const FileSystemURL& url) = 0;
};
virtual ~WatcherManager() {}
virtual void AddObserver(Observer* observer) = 0;
virtual void RemoveObserver(Observer* observer) = 0;
virtual bool HasObserver(Observer* observer) const = 0;
// Observes a directory entry. If the |recursive| mode is not supported then
// FILE_ERROR_INVALID_OPERATION must be returned as an error. If the |url| is
// already watched, or setting up the watcher fails, then |callback|
// must be called with a specific error code. Otherwise |callback| must be
// called with the FILE_OK error code.
virtual void WatchDirectory(const FileSystemURL& url,
bool recursive,
const StatusCallback& callback) = 0;
// Stops observing an entry represented by |url|.
virtual void UnwatchEntry(const FileSystemURL& url,
const StatusCallback& callback) = 0;
};
} // namespace storage
#endif // WEBKIT_BROWSER_FILEAPI_WATCHER_MANAGER_H_
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment