Commit 66a5940f authored by kmadhusu@chromium.org's avatar kmadhusu@chromium.org

(1) Added a recursive boolean param to FilePathWatcher::Watch() function to...

(1) Added a recursive boolean param to FilePathWatcher::Watch() function to watch for sub directory tree changes. Fixed all the calling sites.
(2) Added support to watch sub trees on Windows.
(3) Added FilePathWatcherTest.RecursiveWatch browser test.

BUG=144491
TEST=none


Review URL: https://chromiumcodereview.appspot.com/11415066

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@171097 0039d316-1c4b-4281-b951-d872f2087c98
parent ef442aa7
...@@ -52,7 +52,7 @@ void FilePathWatcher::CancelWatch( ...@@ -52,7 +52,7 @@ void FilePathWatcher::CancelWatch(
bool FilePathWatcher::Watch(const FilePath& path, Delegate* delegate) { bool FilePathWatcher::Watch(const FilePath& path, Delegate* delegate) {
DCHECK(path.IsAbsolute()); DCHECK(path.IsAbsolute());
return impl_->Watch(path, delegate); return impl_->Watch(path, false, delegate);
} }
FilePathWatcher::PlatformDelegate::PlatformDelegate(): cancelled_(false) { FilePathWatcher::PlatformDelegate::PlatformDelegate(): cancelled_(false) {
...@@ -62,8 +62,11 @@ FilePathWatcher::PlatformDelegate::~PlatformDelegate() { ...@@ -62,8 +62,11 @@ FilePathWatcher::PlatformDelegate::~PlatformDelegate() {
DCHECK(is_cancelled()); DCHECK(is_cancelled());
} }
bool FilePathWatcher::Watch(const FilePath& path, const Callback& callback) { bool FilePathWatcher::Watch(const FilePath& path,
return Watch(path, new FilePathWatcherDelegate(callback)); bool recursive,
const Callback& callback) {
DCHECK(path.IsAbsolute());
return impl_->Watch(path, recursive, new FilePathWatcherDelegate(callback));
} }
} // namespace files } // namespace files
......
...@@ -59,6 +59,7 @@ class BASE_EXPORT FilePathWatcher { ...@@ -59,6 +59,7 @@ class BASE_EXPORT FilePathWatcher {
// Start watching for the given |path| and notify |delegate| about changes. // Start watching for the given |path| and notify |delegate| about changes.
virtual bool Watch(const FilePath& path, virtual bool Watch(const FilePath& path,
bool recursive,
Delegate* delegate) WARN_UNUSED_RESULT = 0; Delegate* delegate) WARN_UNUSED_RESULT = 0;
// Stop watching. This is called from FilePathWatcher's dtor in order to // Stop watching. This is called from FilePathWatcher's dtor in order to
...@@ -119,9 +120,13 @@ class BASE_EXPORT FilePathWatcher { ...@@ -119,9 +120,13 @@ class BASE_EXPORT FilePathWatcher {
WARN_UNUSED_RESULT; WARN_UNUSED_RESULT;
// Invokes |callback| whenever updates to |path| are detected. This should be // Invokes |callback| whenever updates to |path| are detected. This should be
// called at most once, and from a MessageLoop of TYPE_IO. The callback will // called at most once, and from a MessageLoop of TYPE_IO. Set |recursive| to
// be invoked on the same loop. Returns true on success. // true, to watch |path| and its children. The callback will be invoked on
bool Watch(const FilePath& path, const Callback& callback); // the same loop. Returns true on success.
//
// NOTE: Recursive watch is not supported on all platforms and file systems.
// Watch() will return false in the case of failure.
bool Watch(const FilePath& path, bool recursive, const Callback& callback);
private: private:
scoped_refptr<PlatformDelegate> impl_; scoped_refptr<PlatformDelegate> impl_;
......
This diff is collapsed.
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include "base/bind.h" #include "base/bind.h"
#include "base/file_util.h" #include "base/file_util.h"
#include "base/logging.h"
#include "base/message_loop.h" #include "base/message_loop.h"
#include "base/message_loop_proxy.h" #include "base/message_loop_proxy.h"
#include "base/stringprintf.h" #include "base/stringprintf.h"
...@@ -64,6 +65,7 @@ class FilePathWatcherImpl : public FilePathWatcher::PlatformDelegate, ...@@ -64,6 +65,7 @@ class FilePathWatcherImpl : public FilePathWatcher::PlatformDelegate,
// FilePathWatcher::PlatformDelegate overrides. // FilePathWatcher::PlatformDelegate overrides.
virtual bool Watch(const FilePath& path, virtual bool Watch(const FilePath& path,
bool recursive,
FilePathWatcher::Delegate* delegate) OVERRIDE; FilePathWatcher::Delegate* delegate) OVERRIDE;
virtual void Cancel() OVERRIDE; virtual void Cancel() OVERRIDE;
...@@ -428,12 +430,19 @@ void FilePathWatcherImpl::WillDestroyCurrentMessageLoop() { ...@@ -428,12 +430,19 @@ void FilePathWatcherImpl::WillDestroyCurrentMessageLoop() {
} }
bool FilePathWatcherImpl::Watch(const FilePath& path, bool FilePathWatcherImpl::Watch(const FilePath& path,
bool recursive,
FilePathWatcher::Delegate* delegate) { FilePathWatcher::Delegate* delegate) {
DCHECK(MessageLoopForIO::current()); DCHECK(MessageLoopForIO::current());
DCHECK(target_.value().empty()); // Can only watch one path. DCHECK(target_.value().empty()); // Can only watch one path.
DCHECK(delegate); DCHECK(delegate);
DCHECK_EQ(kqueue_, -1); DCHECK_EQ(kqueue_, -1);
if (recursive) {
// Recursive watch is not supported on this platform.
NOTIMPLEMENTED();
return false;
}
delegate_ = delegate; delegate_ = delegate;
target_ = path; target_ = path;
......
...@@ -100,6 +100,7 @@ class FilePathWatcherImpl : public FilePathWatcher::PlatformDelegate, ...@@ -100,6 +100,7 @@ class FilePathWatcherImpl : public FilePathWatcher::PlatformDelegate,
// Start watching |path| for changes and notify |delegate| on each change. // Start watching |path| for changes and notify |delegate| on each change.
// Returns true if watch for |path| has been added successfully. // Returns true if watch for |path| has been added successfully.
virtual bool Watch(const FilePath& path, virtual bool Watch(const FilePath& path,
bool recursive,
FilePathWatcher::Delegate* delegate) OVERRIDE; FilePathWatcher::Delegate* delegate) OVERRIDE;
// Cancel the watch. This unregisters the instance with InotifyReader. // Cancel the watch. This unregisters the instance with InotifyReader.
...@@ -361,9 +362,15 @@ void FilePathWatcherImpl::OnFilePathChanged(InotifyReader::Watch fired_watch, ...@@ -361,9 +362,15 @@ void FilePathWatcherImpl::OnFilePathChanged(InotifyReader::Watch fired_watch,
} }
bool FilePathWatcherImpl::Watch(const FilePath& path, bool FilePathWatcherImpl::Watch(const FilePath& path,
bool recursive,
FilePathWatcher::Delegate* delegate) { FilePathWatcher::Delegate* delegate) {
DCHECK(target_.empty()); DCHECK(target_.empty());
DCHECK(MessageLoopForIO::current()); DCHECK(MessageLoopForIO::current());
if (recursive) {
// Recursive watch is not supported on this platform.
NOTIMPLEMENTED();
return false;
}
set_message_loop(base::MessageLoopProxy::current()); set_message_loop(base::MessageLoopProxy::current());
delegate_ = delegate; delegate_ = delegate;
......
...@@ -15,6 +15,7 @@ namespace { ...@@ -15,6 +15,7 @@ namespace {
class FilePathWatcherImpl : public FilePathWatcher::PlatformDelegate { class FilePathWatcherImpl : public FilePathWatcher::PlatformDelegate {
public: public:
virtual bool Watch(const FilePath& path, virtual bool Watch(const FilePath& path,
bool recursive,
FilePathWatcher::Delegate* delegate) OVERRIDE { FilePathWatcher::Delegate* delegate) OVERRIDE {
return false; return false;
} }
......
...@@ -22,10 +22,14 @@ class FilePathWatcherImpl : public FilePathWatcher::PlatformDelegate, ...@@ -22,10 +22,14 @@ class FilePathWatcherImpl : public FilePathWatcher::PlatformDelegate,
public base::win::ObjectWatcher::Delegate, public base::win::ObjectWatcher::Delegate,
public MessageLoop::DestructionObserver { public MessageLoop::DestructionObserver {
public: public:
FilePathWatcherImpl() : delegate_(NULL), handle_(INVALID_HANDLE_VALUE) {} FilePathWatcherImpl()
: delegate_(NULL),
handle_(INVALID_HANDLE_VALUE),
recursive_watch_(false) {}
// FilePathWatcher::PlatformDelegate overrides. // FilePathWatcher::PlatformDelegate overrides.
virtual bool Watch(const FilePath& path, virtual bool Watch(const FilePath& path,
bool recursive,
FilePathWatcher::Delegate* delegate) OVERRIDE; FilePathWatcher::Delegate* delegate) OVERRIDE;
virtual void Cancel() OVERRIDE; virtual void Cancel() OVERRIDE;
...@@ -40,11 +44,13 @@ class FilePathWatcherImpl : public FilePathWatcher::PlatformDelegate, ...@@ -40,11 +44,13 @@ class FilePathWatcherImpl : public FilePathWatcher::PlatformDelegate,
private: private:
virtual ~FilePathWatcherImpl() {} virtual ~FilePathWatcherImpl() {}
// Setup a watch handle for directory |dir|. Returns true if no fatal error // Setup a watch handle for directory |dir|. Set |recursive| to true to watch
// occurs. |handle| will receive the handle value if |dir| is watchable, // the directory sub trees. Returns true if no fatal error occurs. |handle|
// otherwise INVALID_HANDLE_VALUE. // will receive the handle value if |dir| is watchable, otherwise
static bool SetupWatchHandle(const FilePath& dir, HANDLE* handle) // INVALID_HANDLE_VALUE.
WARN_UNUSED_RESULT; static bool SetupWatchHandle(const FilePath& dir,
bool recursive,
HANDLE* handle) WARN_UNUSED_RESULT;
// (Re-)Initialize the watch handle. // (Re-)Initialize the watch handle.
bool UpdateWatch() WARN_UNUSED_RESULT; bool UpdateWatch() WARN_UNUSED_RESULT;
...@@ -67,6 +73,9 @@ class FilePathWatcherImpl : public FilePathWatcher::PlatformDelegate, ...@@ -67,6 +73,9 @@ class FilePathWatcherImpl : public FilePathWatcher::PlatformDelegate,
// ObjectWatcher to watch handle_ for events. // ObjectWatcher to watch handle_ for events.
base::win::ObjectWatcher watcher_; base::win::ObjectWatcher watcher_;
// Set to true to watch the sub trees of the specified directory file path.
bool recursive_watch_;
// Keep track of the last modified time of the file. We use nulltime // Keep track of the last modified time of the file. We use nulltime
// to represent the file not existing. // to represent the file not existing.
base::Time last_modified_; base::Time last_modified_;
...@@ -79,12 +88,14 @@ class FilePathWatcherImpl : public FilePathWatcher::PlatformDelegate, ...@@ -79,12 +88,14 @@ class FilePathWatcherImpl : public FilePathWatcher::PlatformDelegate,
}; };
bool FilePathWatcherImpl::Watch(const FilePath& path, bool FilePathWatcherImpl::Watch(const FilePath& path,
bool recursive,
FilePathWatcher::Delegate* delegate) { FilePathWatcher::Delegate* delegate) {
DCHECK(target_.value().empty()); // Can only watch one path. DCHECK(target_.value().empty()); // Can only watch one path.
set_message_loop(base::MessageLoopProxy::current()); set_message_loop(base::MessageLoopProxy::current());
delegate_ = delegate; delegate_ = delegate;
target_ = path; target_ = path;
recursive_watch_ = recursive;
MessageLoop::current()->AddDestructionObserver(this); MessageLoop::current()->AddDestructionObserver(this);
if (!UpdateWatch()) if (!UpdateWatch())
...@@ -179,16 +190,17 @@ void FilePathWatcherImpl::OnObjectSignaled(HANDLE object) { ...@@ -179,16 +190,17 @@ void FilePathWatcherImpl::OnObjectSignaled(HANDLE object) {
// static // static
bool FilePathWatcherImpl::SetupWatchHandle(const FilePath& dir, bool FilePathWatcherImpl::SetupWatchHandle(const FilePath& dir,
bool recursive,
HANDLE* handle) { HANDLE* handle) {
*handle = FindFirstChangeNotification( *handle = FindFirstChangeNotification(
dir.value().c_str(), dir.value().c_str(),
false, // Don't watch subtrees recursive,
FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_SIZE | FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_SIZE |
FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_DIR_NAME |
FILE_NOTIFY_CHANGE_ATTRIBUTES | FILE_NOTIFY_CHANGE_SECURITY); FILE_NOTIFY_CHANGE_ATTRIBUTES | FILE_NOTIFY_CHANGE_SECURITY);
if (*handle != INVALID_HANDLE_VALUE) { if (*handle != INVALID_HANDLE_VALUE) {
// Make sure the handle we got points to an existing directory. It seems // Make sure the handle we got points to an existing directory. It seems
// that windows sometimes hands out watches to direectories that are // that windows sometimes hands out watches to directories that are
// about to go away, but doesn't sent notifications if that happens. // about to go away, but doesn't sent notifications if that happens.
if (!file_util::DirectoryExists(dir)) { if (!file_util::DirectoryExists(dir)) {
FindCloseChangeNotification(*handle); FindCloseChangeNotification(*handle);
...@@ -232,7 +244,7 @@ bool FilePathWatcherImpl::UpdateWatch() { ...@@ -232,7 +244,7 @@ bool FilePathWatcherImpl::UpdateWatch() {
std::vector<FilePath> child_dirs; std::vector<FilePath> child_dirs;
FilePath watched_path(target_); FilePath watched_path(target_);
while (true) { while (true) {
if (!SetupWatchHandle(watched_path, &handle_)) if (!SetupWatchHandle(watched_path, recursive_watch_, &handle_))
return false; return false;
// Break if a valid handle is returned. Try the parent directory otherwise. // Break if a valid handle is returned. Try the parent directory otherwise.
...@@ -256,7 +268,7 @@ bool FilePathWatcherImpl::UpdateWatch() { ...@@ -256,7 +268,7 @@ bool FilePathWatcherImpl::UpdateWatch() {
watched_path = watched_path.Append(child_dirs.back()); watched_path = watched_path.Append(child_dirs.back());
child_dirs.pop_back(); child_dirs.pop_back();
HANDLE temp_handle = INVALID_HANDLE_VALUE; HANDLE temp_handle = INVALID_HANDLE_VALUE;
if (!SetupWatchHandle(watched_path, &temp_handle)) if (!SetupWatchHandle(watched_path, recursive_watch_, &temp_handle))
return false; return false;
if (temp_handle == INVALID_HANDLE_VALUE) if (temp_handle == INVALID_HANDLE_VALUE)
break; break;
......
...@@ -38,8 +38,9 @@ ConfigDirPolicyLoader::~ConfigDirPolicyLoader() {} ...@@ -38,8 +38,9 @@ ConfigDirPolicyLoader::~ConfigDirPolicyLoader() {}
void ConfigDirPolicyLoader::InitOnFile() { void ConfigDirPolicyLoader::InitOnFile() {
base::files::FilePathWatcher::Callback callback = base::files::FilePathWatcher::Callback callback =
base::Bind(&ConfigDirPolicyLoader::OnFileUpdated, base::Unretained(this)); base::Bind(&ConfigDirPolicyLoader::OnFileUpdated, base::Unretained(this));
mandatory_watcher_.Watch(config_dir_.Append(kMandatoryConfigDir), callback); mandatory_watcher_.Watch(config_dir_.Append(kMandatoryConfigDir), false,
recommended_watcher_.Watch(config_dir_.Append(kRecommendedConfigDir), callback);
recommended_watcher_.Watch(config_dir_.Append(kRecommendedConfigDir), false,
callback); callback);
} }
......
...@@ -88,7 +88,7 @@ PolicyLoaderMac::~PolicyLoaderMac() {} ...@@ -88,7 +88,7 @@ PolicyLoaderMac::~PolicyLoaderMac() {}
void PolicyLoaderMac::InitOnFile() { void PolicyLoaderMac::InitOnFile() {
if (!managed_policy_path_.empty()) { if (!managed_policy_path_.empty()) {
watcher_.Watch( watcher_.Watch(
managed_policy_path_, managed_policy_path_, false,
base::Bind(&PolicyLoaderMac::OnFileUpdated, base::Unretained(this))); base::Bind(&PolicyLoaderMac::OnFileUpdated, base::Unretained(this)));
} }
} }
......
...@@ -331,7 +331,7 @@ void RemovableDeviceNotificationsLinux::InitOnFileThread() { ...@@ -331,7 +331,7 @@ void RemovableDeviceNotificationsLinux::InitOnFileThread() {
// RemovableDeviceNotificationsLinux will live longer than expected, and // RemovableDeviceNotificationsLinux will live longer than expected, and
// FilePathWatcher will get in trouble at shutdown time. // FilePathWatcher will get in trouble at shutdown time.
bool ret = file_watcher_.Watch( bool ret = file_watcher_.Watch(
mtab_path_, mtab_path_, false,
base::Bind(&RemovableDeviceNotificationsLinux::OnFilePathChanged, base::Bind(&RemovableDeviceNotificationsLinux::OnFilePathChanged,
base::Unretained(this))); base::Unretained(this)));
if (!ret) { if (!ret) {
......
...@@ -59,7 +59,7 @@ class ConfigWatcher { ...@@ -59,7 +59,7 @@ class ConfigWatcher {
bool Watch(const CallbackType& callback) { bool Watch(const CallbackType& callback) {
callback_ = callback; callback_ = callback;
return watcher_.Watch(FilePath(kFilePathConfig), return watcher_.Watch(FilePath(kFilePathConfig), false,
base::Bind(&ConfigWatcher::OnCallback, base::Bind(&ConfigWatcher::OnCallback,
base::Unretained(this))); base::Unretained(this)));
} }
...@@ -120,7 +120,7 @@ class DnsConfigServicePosix::Watcher { ...@@ -120,7 +120,7 @@ class DnsConfigServicePosix::Watcher {
LOG(ERROR) << "DNS config watch failed to start."; LOG(ERROR) << "DNS config watch failed to start.";
success = false; success = false;
} }
if (!hosts_watcher_.Watch(FilePath(kFilePathHosts), if (!hosts_watcher_.Watch(FilePath(kFilePathHosts), false,
base::Bind(&Watcher::OnHostsChanged, base::Bind(&Watcher::OnHostsChanged,
base::Unretained(this)))) { base::Unretained(this)))) {
LOG(ERROR) << "DNS hosts watch failed to start."; LOG(ERROR) << "DNS hosts watch failed to start.";
......
...@@ -529,7 +529,7 @@ class DnsConfigServiceWin::Watcher ...@@ -529,7 +529,7 @@ class DnsConfigServiceWin::Watcher
dnscache_watcher_.Watch(kDnscachePath, callback); dnscache_watcher_.Watch(kDnscachePath, callback);
policy_watcher_.Watch(kPolicyPath, callback); policy_watcher_.Watch(kPolicyPath, callback);
if (!hosts_watcher_.Watch(GetHostsPath(), if (!hosts_watcher_.Watch(GetHostsPath(), false,
base::Bind(&Watcher::OnHostsChanged, base::Bind(&Watcher::OnHostsChanged,
base::Unretained(this)))) { base::Unretained(this)))) {
LOG(ERROR) << "DNS hosts watch failed to start."; LOG(ERROR) << "DNS hosts watch failed to start.";
...@@ -703,4 +703,3 @@ scoped_ptr<DnsConfigService> DnsConfigService::CreateSystemService() { ...@@ -703,4 +703,3 @@ scoped_ptr<DnsConfigService> DnsConfigService::CreateSystemService() {
} }
} // namespace net } // namespace net
...@@ -122,8 +122,8 @@ void ConfigFileWatcherImpl::Watch(const FilePath& config_path) { ...@@ -122,8 +122,8 @@ void ConfigFileWatcherImpl::Watch(const FilePath& config_path) {
config_watcher_.reset(new base::files::FilePathWatcher()); config_watcher_.reset(new base::files::FilePathWatcher());
config_path_ = config_path; config_path_ = config_path;
if (!config_watcher_->Watch( if (!config_watcher_->Watch(
config_path_, config_path_, false,
base::Bind(&ConfigFileWatcherImpl::OnConfigUpdated, this))) { base::Bind(&ConfigFileWatcherImpl::OnConfigUpdated, this))) {
LOG(ERROR) << "Couldn't watch file '" << config_path_.value() << "'"; LOG(ERROR) << "Couldn't watch file '" << config_path_.value() << "'";
main_task_runner_->PostTask( main_task_runner_->PostTask(
FROM_HERE, FROM_HERE,
......
...@@ -68,7 +68,7 @@ class PolicyWatcherLinux : public PolicyWatcher { ...@@ -68,7 +68,7 @@ class PolicyWatcherLinux : public PolicyWatcher {
if (!config_dir_.empty() && if (!config_dir_.empty() &&
!watcher_->Watch( !watcher_->Watch(
config_dir_, config_dir_, false,
base::Bind(&PolicyWatcherLinux::OnFilePathChanged, base::Bind(&PolicyWatcherLinux::OnFilePathChanged,
weak_factory_.GetWeakPtr()))) { weak_factory_.GetWeakPtr()))) {
OnFilePathChanged(config_dir_, true); OnFilePathChanged(config_dir_, true);
......
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