Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(2982)

Unified Diff: base/files/file_path_watcher_linux.cc

Issue 7583034: [Linux] Make FilePathWatcher somewhat more symlink aware. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: try watching symlink's dir Created 9 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: base/files/file_path_watcher_linux.cc
diff --git a/base/files/file_path_watcher_linux.cc b/base/files/file_path_watcher_linux.cc
index 0fb10e4590e448dadb90f23e5492e153efce0297..4f682e849dca73b003af1f4b9b3cb3049afce6c3 100644
--- a/base/files/file_path_watcher_linux.cc
+++ b/base/files/file_path_watcher_linux.cc
@@ -119,7 +119,8 @@ class FilePathWatcherImpl : public FilePathWatcher::PlatformDelegate,
// Inotify watches are installed for all directory components of |target_|. A
// WatchEntry instance holds the watch descriptor for a component and the
- // subdirectory for that identifies the next component.
+ // subdirectory for that identifies the next component. If a symbolic link
+ // is being watched, the target of the link is also kept.
struct WatchEntry {
WatchEntry(InotifyReader::Watch watch, const FilePath::StringType& subdir)
: watch_(watch),
@@ -127,6 +128,7 @@ class FilePathWatcherImpl : public FilePathWatcher::PlatformDelegate,
InotifyReader::Watch watch_;
FilePath::StringType subdir_;
+ FilePath::StringType linkname_;
};
typedef std::vector<WatchEntry> WatchVector;
@@ -328,41 +330,43 @@ void FilePathWatcherImpl::OnFilePathChanged(
// Find the entry in |watches_| that corresponds to |fired_watch|.
WatchVector::const_iterator watch_entry(watches_.begin());
for ( ; watch_entry != watches_.end(); ++watch_entry) {
- if (fired_watch == watch_entry->watch_)
- break;
- }
-
- // If this notification is from a previous generation of watches or the watch
- // has been cancelled (|watches_| is empty then), bail out.
- if (watch_entry == watches_.end())
- return;
-
- // Check whether a path component of |target_| changed.
- bool change_on_target_path = child.empty() || child == watch_entry->subdir_;
-
- // Check whether the change references |target_| or a direct child.
- DCHECK(watch_entry->subdir_.empty() || (watch_entry + 1) != watches_.end());
- bool target_changed = watch_entry->subdir_.empty() ||
- (watch_entry->subdir_ == child && (++watch_entry)->subdir_.empty());
+ if (fired_watch == watch_entry->watch_) {
Mattias Nissler (ping if slow) 2011/08/30 09:53:06 What is the reason you don't break this loop? I ca
Craig 2011/08/30 16:00:16 This covers the situation where the symlink is tar
Mattias Nissler (ping if slow) 2011/08/30 16:38:26 I see. Fair enough.
+ // Check whether a path component of |target_| changed.
+ bool change_on_target_path = child.empty() ||
+ ((child == watch_entry->subdir_) && watch_entry->linkname_.empty());
+
+ // Check whether the change references |target_| or a direct child.
+ DCHECK(watch_entry->subdir_.empty() ||
+ (watch_entry + 1) != watches_.end());
+ bool target_changed =
+ (watch_entry->subdir_.empty() && (child == watch_entry->linkname_)) ||
Mattias Nissler (ping if slow) 2011/08/30 09:53:06 What if the link occurs somewhere in the middle of
Craig 2011/08/30 16:00:16 The watch for a symlink's target directory is only
Mattias Nissler (ping if slow) 2011/08/30 16:38:26 I don't understand where in the code we reject sym
Craig 2011/09/01 19:04:08 Nothing stops the client from calling us with a sy
+ (watch_entry->subdir_.empty() && watch_entry->linkname_.empty()) ||
+ (watch_entry->subdir_ == child && (watch_entry + 1)->subdir_.empty());
+
+ // Update watches if a directory component of the |target_| path
+ // (dis)appears.
+ if (is_directory && change_on_target_path && !UpdateWatches()) {
+ delegate_->OnFilePathError(target_);
+ return;
+ }
- // Update watches if a directory component of the |target_| path (dis)appears.
- if (is_directory && change_on_target_path && !UpdateWatches()) {
- delegate_->OnFilePathError(target_);
- return;
+ // Report the following events:
+ // - The target or a direct child of the target got changed (in case the
+ // watched path refers to a directory).
+ // - One of the parent directories got moved or deleted, since the target
+ // disappears in this case.
+ // - One of the parent directories appears. The event corresponding to
+ // the target appearing might have been missed in this case, so
+ // recheck.
+ if (target_changed ||
+ (change_on_target_path && !created) ||
+ (change_on_target_path && file_util::PathExists(target_))) {
+ delegate_->OnFilePathChanged(target_);
+ return;
+ }
+ }
}
- // Report the following events:
- // - The target or a direct child of the target got changed (in case the
- // watched path refers to a directory).
- // - One of the parent directories got moved or deleted, since the target
- // disappears in this case.
- // - One of the parent directories appears. The event corresponding to the
- // target appearing might have been missed in this case, so recheck.
- if (target_changed ||
- (change_on_target_path && !created) ||
- (change_on_target_path && file_util::PathExists(target_))) {
- delegate_->OnFilePathChanged(target_);
- }
}
bool FilePathWatcherImpl::Watch(const FilePath& path,
@@ -436,6 +440,18 @@ bool FilePathWatcherImpl::UpdateWatches() {
InotifyReader::Watch old_watch = watch_entry->watch_;
if (path_valid) {
watch_entry->watch_ = g_inotify_reader.Get().AddWatch(path, this);
+ if ((watch_entry->watch_ == InotifyReader::kInvalidWatch) &&
+ file_util::IsLink(path)) {
Mattias Nissler (ping if slow) 2011/08/30 09:53:06 We're not passing IN_DONT_FOLLOW, so this only kic
Craig 2011/08/30 16:00:16 AddWatch will fail when called with a filename or
Mattias Nissler (ping if slow) 2011/08/30 16:38:26 How can we be sure there is no symlink on the path
Craig 2011/09/01 19:04:08 Yep, I missed that :(
+ FilePath link;
+ file_util::ReadSymbolicLink(path, &link);
+ if (!link.IsAbsolute())
+ link = path.DirName().Append(link);
+ // Try watching symlink target directory.
+ watch_entry->watch_ =
+ g_inotify_reader.Get().AddWatch(link.DirName(), this);
Mattias Nissler (ping if slow) 2011/08/30 09:53:06 So we fail here if the immediate parent directory
Craig 2011/08/30 16:00:16 Yes. In the final solution I'd like to add watches
Mattias Nissler (ping if slow) 2011/08/30 16:38:26 Sounds good.
+ if (watch_entry->watch_ != InotifyReader::kInvalidWatch)
+ watch_entry->linkname_ = link.BaseName().value();
+ }
if (watch_entry->watch_ == InotifyReader::kInvalidWatch) {
path_valid = false;
}
« base/files/file_path_watcher_browsertest.cc ('K') | « base/files/file_path_watcher_browsertest.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698