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