diff options
Diffstat (limited to 'base')
-rw-r--r-- | base/directory_watcher.h | 15 | ||||
-rw-r--r-- | base/directory_watcher_inotify.cc | 321 | ||||
-rw-r--r-- | base/directory_watcher_mac.cc | 3 | ||||
-rw-r--r-- | base/directory_watcher_stub.cc | 2 | ||||
-rw-r--r-- | base/directory_watcher_unittest.cc | 49 | ||||
-rw-r--r-- | base/directory_watcher_win.cc | 5 | ||||
-rw-r--r-- | base/file_util.h | 6 | ||||
-rw-r--r-- | base/file_util_posix.cc | 10 |
8 files changed, 294 insertions, 117 deletions
diff --git a/base/directory_watcher.h b/base/directory_watcher.h index ae01149..2d5b901 100644 --- a/base/directory_watcher.h +++ b/base/directory_watcher.h @@ -11,6 +11,7 @@ #include "base/ref_counted.h" class FilePath; +class MessageLoop; // This class lets you register interest in changes on a directory. // The delegate will get called whenever a file is added or changed in the @@ -19,6 +20,7 @@ class DirectoryWatcher { public: class Delegate { public: + virtual ~Delegate() {} virtual void OnDirectoryChanged(const FilePath& path) = 0; }; @@ -27,15 +29,18 @@ class DirectoryWatcher { // Register interest in any changes in the directory |path|. // OnDirectoryChanged will be called back for each change within the dir. - // If |recursive| is true, the delegate will be notified for each change - // within the directory tree starting at |path|. Returns false on error. + // Any background operations will be ran on |backend_loop|, or inside Watch + // if |backend_loop| is NULL. If |recursive| is true, the delegate will be + // notified for each change within the directory tree starting at |path|. + // Returns false on error. // // Note: on Windows you may got more notifications for non-recursive watch // than you expect, especially on versions earlier than Vista. The behavior // is consistent on any particular version of Windows, but not across // different versions. - bool Watch(const FilePath& path, Delegate* delegate, bool recursive) { - return impl_->Watch(path, delegate, recursive); + bool Watch(const FilePath& path, Delegate* delegate, + MessageLoop* backend_loop, bool recursive) { + return impl_->Watch(path, delegate, backend_loop, recursive); } // Used internally to encapsulate different members on different platforms. @@ -43,7 +48,7 @@ class DirectoryWatcher { public: virtual ~PlatformDelegate() {} virtual bool Watch(const FilePath& path, Delegate* delegate, - bool recursive) = 0; + MessageLoop* backend_loop, bool recursive) = 0; }; private: diff --git a/base/directory_watcher_inotify.cc b/base/directory_watcher_inotify.cc index 86e7bd9..ee42127 100644 --- a/base/directory_watcher_inotify.cc +++ b/base/directory_watcher_inotify.cc @@ -6,8 +6,8 @@ #include <errno.h> #include <string.h> -#include <sys/ioctl.h> #include <sys/inotify.h> +#include <sys/ioctl.h> #include <sys/select.h> #include <unistd.h> @@ -18,6 +18,7 @@ #include "base/eintr_wrapper.h" #include "base/file_path.h" +#include "base/file_util.h" #include "base/hash_tables.h" #include "base/lock.h" #include "base/logging.h" @@ -26,43 +27,38 @@ #include "base/singleton.h" #include "base/task.h" #include "base/thread.h" +#include "base/waitable_event.h" namespace { +class DirectoryWatcherImpl; + // Singleton to manage all inotify watches. class InotifyReader { public: typedef int Watch; // Watch descriptor used by AddWatch and RemoveWatch. static const Watch kInvalidWatch = -1; - // Watch |path| for changes. |delegate| will be notified on each change. Does - // not check for duplicates. If you call it n times with same |path| - // and |delegate|, it will receive n notifications for each change - // in |path|. It makes implementation of DirectoryWatcher simple. + // Watch |path| for changes. |watcher| will be notified on each change. // Returns kInvalidWatch on failure. - Watch AddWatch(const FilePath& path, DirectoryWatcher::Delegate* delegate); + Watch AddWatch(const FilePath& path, DirectoryWatcherImpl* watcher); - // Remove |watch| for |delegate|. If you had n watches for same |delegate| - // and path, after calling this function you will have n - 1. - // Returns true on success. - bool RemoveWatch(Watch watch, DirectoryWatcher::Delegate* delegate); + // Remove |watch|. Returns true on success. + bool RemoveWatch(Watch watch, DirectoryWatcherImpl* watcher); // Callback for InotifyReaderTask. - void OnInotifyEvent(inotify_event* event); + void OnInotifyEvent(const inotify_event* event); private: friend struct DefaultSingletonTraits<InotifyReader>; - typedef std::pair<DirectoryWatcher::Delegate*, MessageLoop*> DelegateInfo; - typedef std::multiset<DelegateInfo> DelegateSet; + typedef std::set<DirectoryWatcherImpl*> WatcherSet; InotifyReader(); ~InotifyReader(); // We keep track of which delegates want to be notified on which watches. - // Multiset is used because there may be many DirectoryWatchers for same path - // and delegate. - base::hash_map<Watch, DelegateSet> delegates_; + base::hash_map<Watch, WatcherSet> watchers_; // For each watch we also want to know the path it's watching. base::hash_map<Watch, FilePath> paths_; @@ -85,6 +81,114 @@ class InotifyReader { DISALLOW_COPY_AND_ASSIGN(InotifyReader); }; +class DirectoryWatcherImpl : public DirectoryWatcher::PlatformDelegate { + public: + typedef std::set<FilePath> FilePathSet; + + DirectoryWatcherImpl(); + ~DirectoryWatcherImpl(); + + void EnsureSetupFinished(); + + // Called for each event coming from one of watches. + void OnInotifyEvent(const inotify_event* event); + + // Callback for RegisterSubtreeWatchesTask. + bool OnEnumeratedSubtree(const FilePathSet& paths); + + // Start watching |path| for changes and notify |delegate| on each change. + // If |recursive| is true, watch entire subtree. + // Returns true if watch for |path| has been added successfully. Watches + // required for |recursive| are added on a background thread and have no + // effect on the return value. + virtual bool Watch(const FilePath& path, DirectoryWatcher::Delegate* delegate, + MessageLoop* backend_loop, bool recursive); + + private: + typedef std::set<InotifyReader::Watch> WatchSet; + typedef std::set<ino_t> InodeSet; + + // Returns true if |inode| is watched by DirectoryWatcherImpl. + bool IsInodeWatched(ino_t inode) const; + + // Delegate to notify upon changes. + DirectoryWatcher::Delegate* delegate_; + + // Path we're watching (passed to delegate). + FilePath root_path_; + + // Watch returned by InotifyReader. + InotifyReader::Watch watch_; + + // Set of watched inodes. + InodeSet inodes_watched_; + + // Keep track of registered watches. + WatchSet watches_; + + // Lock to protect inodes_watched_ and watches_. + Lock lock_; + + // Flag set to true when recursively watching subtree. + bool recursive_; + + // Loop where we post directory change notifications to. + MessageLoop* loop_; + + // Event signaled when the background task finished adding initial inotify + // watches for recursive watch. + base::WaitableEvent recursive_setup_finished_; + + DISALLOW_COPY_AND_ASSIGN(DirectoryWatcherImpl); +}; + +class RegisterSubtreeWatchesTask : public Task { + public: + RegisterSubtreeWatchesTask(DirectoryWatcherImpl* watcher, + const FilePath& path) + : watcher_(watcher), + path_(path) { + } + + virtual void Run() { + file_util::FileEnumerator dir_list(path_, true, + file_util::FileEnumerator::DIRECTORIES); + + DirectoryWatcherImpl::FilePathSet subtree; + for (FilePath subdirectory = dir_list.Next(); + !subdirectory.empty(); + subdirectory = dir_list.Next()) { + subtree.insert(subdirectory); + } + watcher_->OnEnumeratedSubtree(subtree); + } + + private: + DirectoryWatcherImpl* watcher_; + FilePath path_; + + DISALLOW_COPY_AND_ASSIGN(RegisterSubtreeWatchesTask); +}; + +class DirectoryWatcherImplNotifyTask : public Task { + public: + DirectoryWatcherImplNotifyTask(DirectoryWatcher::Delegate* delegate, + const FilePath& path) + : delegate_(delegate), + path_(path) { + } + + virtual void Run() { + delegate_->OnDirectoryChanged(path_); + } + + private: + DirectoryWatcher::Delegate* delegate_; + FilePath path_; + + DISALLOW_COPY_AND_ASSIGN(DirectoryWatcherImplNotifyTask); +}; + class InotifyReaderTask : public Task { public: InotifyReaderTask(InotifyReader* reader, int inotify_fd, int shutdown_fd) @@ -151,25 +255,6 @@ class InotifyReaderTask : public Task { DISALLOW_COPY_AND_ASSIGN(InotifyReaderTask); }; -class InotifyReaderNotifyTask : public Task { - public: - InotifyReaderNotifyTask(DirectoryWatcher::Delegate* delegate, - const FilePath& path) - : delegate_(delegate), - path_(path) { - } - - virtual void Run() { - delegate_->OnDirectoryChanged(path_); - } - - private: - DirectoryWatcher::Delegate* delegate_; - FilePath path_; - - DISALLOW_COPY_AND_ASSIGN(InotifyReaderNotifyTask); -}; - InotifyReader::InotifyReader() : thread_("inotify_reader"), inotify_fd_(inotify_init()), @@ -199,7 +284,8 @@ InotifyReader::~InotifyReader() { } InotifyReader::Watch InotifyReader::AddWatch( - const FilePath& path, DirectoryWatcher::Delegate* delegate) { + const FilePath& path, DirectoryWatcherImpl* watcher) { + if (!valid_) return kInvalidWatch; @@ -208,19 +294,20 @@ InotifyReader::Watch InotifyReader::AddWatch( Watch watch = inotify_add_watch(inotify_fd_, path.value().c_str(), IN_CREATE | IN_DELETE | IN_CLOSE_WRITE | IN_MOVE); + if (watch == kInvalidWatch) return kInvalidWatch; if (paths_[watch].empty()) paths_[watch] = path; // We don't yet watch this path. - delegates_[watch].insert(std::make_pair(delegate, MessageLoop::current())); + watchers_[watch].insert(watcher); return watch; } bool InotifyReader::RemoveWatch(Watch watch, - DirectoryWatcher::Delegate* delegate) { + DirectoryWatcherImpl* watcher) { if (!valid_) return false; @@ -229,89 +316,148 @@ bool InotifyReader::RemoveWatch(Watch watch, if (paths_[watch].empty()) return false; // We don't recognize this watch. - // Only erase one occurrence of delegate (there may be more). - delegates_[watch].erase( - delegates_[watch].find(std::make_pair(delegate, MessageLoop::current()))); + watchers_[watch].erase(watcher); - if (delegates_[watch].empty()) { + if (watchers_[watch].empty()) { paths_.erase(watch); - delegates_.erase(watch); - + watchers_.erase(watch); return (inotify_rm_watch(inotify_fd_, watch) == 0); } return true; } -void InotifyReader::OnInotifyEvent(inotify_event* event) { +void InotifyReader::OnInotifyEvent(const inotify_event* event) { if (event->mask & IN_IGNORED) return; - DelegateSet delegates_to_notify; + WatcherSet watchers_to_notify; FilePath changed_path; { AutoLock auto_lock(lock_); changed_path = paths_[event->wd]; - delegates_to_notify.insert(delegates_[event->wd].begin(), - delegates_[event->wd].end()); + watchers_to_notify.insert(watchers_[event->wd].begin(), + watchers_[event->wd].end()); } - DelegateSet::iterator i; - for (i = delegates_to_notify.begin(); i != delegates_to_notify.end(); ++i) { - DirectoryWatcher::Delegate* delegate = i->first; - MessageLoop* loop = i->second; - loop->PostTask(FROM_HERE, - new InotifyReaderNotifyTask(delegate, changed_path)); + for (WatcherSet::iterator watcher = watchers_to_notify.begin(); + watcher != watchers_to_notify.end(); + ++watcher) { + (*watcher)->OnInotifyEvent(event); } } -class DirectoryWatcherImpl : public DirectoryWatcher::PlatformDelegate { - public: - DirectoryWatcherImpl() : watch_(InotifyReader::kInvalidWatch) {} - ~DirectoryWatcherImpl(); +DirectoryWatcherImpl::DirectoryWatcherImpl() + : watch_(InotifyReader::kInvalidWatch), + recursive_setup_finished_(false, false) { +} - virtual bool Watch(const FilePath& path, DirectoryWatcher::Delegate* delegate, - bool recursive); +DirectoryWatcherImpl::~DirectoryWatcherImpl() { + if (watch_ == InotifyReader::kInvalidWatch) + return; - private: - // Delegate to notify upon changes. - DirectoryWatcher::Delegate* delegate_; + if (recursive_) + recursive_setup_finished_.Wait(); + for (WatchSet::iterator watch = watches_.begin(); + watch != watches_.end(); + ++watch) { + Singleton<InotifyReader>::get()->RemoveWatch(*watch, this); + } + watches_.clear(); + inodes_watched_.clear(); +} - // Path we're watching (passed to delegate). - FilePath path_; +void DirectoryWatcherImpl::OnInotifyEvent(const inotify_event* event) { + loop_->PostTask(FROM_HERE, + new DirectoryWatcherImplNotifyTask(delegate_, root_path_)); - // Watch returned by InotifyReader. - InotifyReader::Watch watch_; + if (!(event->mask & IN_ISDIR)) + return; - DISALLOW_COPY_AND_ASSIGN(DirectoryWatcherImpl); -}; + if (event->mask & IN_CREATE || event->mask & IN_MOVED_TO) { + // TODO(phajdan.jr): add watch for this new directory. + NOTIMPLEMENTED(); + } else if (event->mask & IN_DELETE || event->mask & IN_MOVED_FROM) { + // TODO(phajdan.jr): remove our watch for this directory. + NOTIMPLEMENTED(); + } +} -DirectoryWatcherImpl::~DirectoryWatcherImpl() { - if (watch_ != InotifyReader::kInvalidWatch) - Singleton<InotifyReader>::get()->RemoveWatch(watch_, delegate_); +bool DirectoryWatcherImpl::IsInodeWatched(ino_t inode) const { + return inodes_watched_.find(inode) != inodes_watched_.end(); } -bool DirectoryWatcherImpl::Watch(const FilePath& path, - DirectoryWatcher::Delegate* delegate, bool recursive) { - DCHECK(watch_ == InotifyReader::kInvalidWatch); // Can only watch one path. - - if (recursive) { - // TODO(phajdan.jr): Support recursive watches. - // Unfortunately inotify has no "native" support for them, but it can be - // emulated by walking the directory tree and setting up watches for each - // directory. Of course this is ineffective for large directory trees. - // For the algorithm, see the link below: - // http://osdir.com/ml/gnome.dashboard.devel/2004-10/msg00022.html - NOTIMPLEMENTED(); +bool DirectoryWatcherImpl::OnEnumeratedSubtree(const FilePathSet& subtree) { + DCHECK(recursive_); + + if (watch_ == InotifyReader::kInvalidWatch) { + recursive_setup_finished_.Signal(); return false; } + bool success = true; + AutoLock auto_lock(lock_); + for (FilePathSet::iterator subdirectory = subtree.begin(); + subdirectory != subtree.end(); + ++subdirectory) { + ino_t inode; + if (!file_util::GetInode(*subdirectory, &inode)) { + success = false; + continue; + } + if (IsInodeWatched(inode)) + continue; + InotifyReader::Watch watch = + Singleton<InotifyReader>::get()->AddWatch(*subdirectory, this); + if (watch != InotifyReader::kInvalidWatch) { + watches_.insert(watch); + inodes_watched_.insert(inode); + } + } + recursive_setup_finished_.Signal(); + return success; +} + +bool DirectoryWatcherImpl::Watch(const FilePath& path, + DirectoryWatcher::Delegate* delegate, + MessageLoop* backend_loop, bool recursive) { + + // Can only watch one path. + DCHECK(watch_ == InotifyReader::kInvalidWatch); + + ino_t inode; + if (!file_util::GetInode(path, &inode)) + return false; + + InotifyReader::Watch watch = + Singleton<InotifyReader>::get()->AddWatch(path, this); + if (watch == InotifyReader::kInvalidWatch) + return false; + delegate_ = delegate; - path_ = path; - watch_ = Singleton<InotifyReader>::get()->AddWatch(path, delegate_); + recursive_ = recursive; + root_path_ = path; + watch_ = watch; + loop_ = MessageLoop::current(); + + { + AutoLock auto_lock(lock_); + inodes_watched_.insert(inode); + watches_.insert(watch_); + } + + if (recursive_) { + Task* subtree_task = new RegisterSubtreeWatchesTask(this, root_path_); + if (backend_loop) { + backend_loop->PostTask(FROM_HERE, subtree_task); + } else { + subtree_task->Run(); + delete subtree_task; + } + } - return watch_ != InotifyReader::kInvalidWatch; + return true; } } // namespace @@ -319,3 +465,4 @@ bool DirectoryWatcherImpl::Watch(const FilePath& path, DirectoryWatcher::DirectoryWatcher() { impl_ = new DirectoryWatcherImpl(); } + diff --git a/base/directory_watcher_mac.cc b/base/directory_watcher_mac.cc index d4b3082..dc3eba6 100644 --- a/base/directory_watcher_mac.cc +++ b/base/directory_watcher_mac.cc @@ -28,7 +28,7 @@ class DirectoryWatcherImpl : public DirectoryWatcher::PlatformDelegate { } virtual bool Watch(const FilePath& path, DirectoryWatcher::Delegate* delegate, - bool recursive); + MessageLoop* backend_loop, bool recursive); void OnFSEventsCallback(const FilePath& event_path) { DCHECK(!path_.value().empty()); @@ -72,6 +72,7 @@ void FSEventsCallback(ConstFSEventStreamRef stream, bool DirectoryWatcherImpl::Watch(const FilePath& path, DirectoryWatcher::Delegate* delegate, + MessageLoop* backend_loop, bool recursive) { DCHECK(path_.value().empty()); // Can only watch one path. diff --git a/base/directory_watcher_stub.cc b/base/directory_watcher_stub.cc index a92a84c..92cc5ff 100644 --- a/base/directory_watcher_stub.cc +++ b/base/directory_watcher_stub.cc @@ -10,7 +10,7 @@ class DirectoryWatcherImpl : public DirectoryWatcher::PlatformDelegate { public: virtual bool Watch(const FilePath& path, DirectoryWatcher::Delegate* delegate, - bool recursive) { + MessageLoop* backend_loop, bool recursive) { return false; } }; diff --git a/base/directory_watcher_unittest.cc b/base/directory_watcher_unittest.cc index 6a2abc9..1b15de8 100644 --- a/base/directory_watcher_unittest.cc +++ b/base/directory_watcher_unittest.cc @@ -13,6 +13,7 @@ #include "base/path_service.h" #include "base/platform_thread.h" #include "base/string_util.h" +#include "base/thread.h" #if defined(OS_WIN) #include "base/win_util.h" #endif // defined(OS_WIN) @@ -151,7 +152,7 @@ class TestDelegate : public DirectoryWatcher::Delegate { TEST_F(DirectoryWatcherTest, NewFile) { DirectoryWatcher watcher; TestDelegate delegate(this); - ASSERT_TRUE(watcher.Watch(test_dir_, &delegate, false)); + ASSERT_TRUE(watcher.Watch(test_dir_, &delegate, NULL, false)); SetExpectedNumberOfNotifiedDelegates(1); ASSERT_TRUE(WriteTestFile(test_dir_.AppendASCII("test_file"), "content")); @@ -166,7 +167,7 @@ TEST_F(DirectoryWatcherTest, ModifiedFile) { DirectoryWatcher watcher; TestDelegate delegate(this); - ASSERT_TRUE(watcher.Watch(test_dir_, &delegate, false)); + ASSERT_TRUE(watcher.Watch(test_dir_, &delegate, NULL, false)); // Now make sure we get notified if the file is modified. SetExpectedNumberOfNotifiedDelegates(1); @@ -181,7 +182,7 @@ TEST_F(DirectoryWatcherTest, DeletedFile) { DirectoryWatcher watcher; TestDelegate delegate(this); - ASSERT_TRUE(watcher.Watch(test_dir_, &delegate, false)); + ASSERT_TRUE(watcher.Watch(test_dir_, &delegate, NULL, false)); // Now make sure we get notified if the file is deleted. SetExpectedNumberOfNotifiedDelegates(1); @@ -195,7 +196,7 @@ TEST_F(DirectoryWatcherTest, Unregister) { { DirectoryWatcher watcher; - ASSERT_TRUE(watcher.Watch(test_dir_, &delegate, false)); + ASSERT_TRUE(watcher.Watch(test_dir_, &delegate, NULL, false)); // And then let it fall out of scope, clearing its watch. } @@ -209,15 +210,10 @@ TEST_F(DirectoryWatcherTest, Unregister) { TEST_F(DirectoryWatcherTest, SubDirRecursive) { FilePath subdir(CreateTestDirDirectoryASCII("SubDir", true)); -#if defined(OS_LINUX) - // TODO(port): Recursive watches are not implemented on Linux. - return; -#endif // !defined(OS_WIN) - // Verify that modifications to a subdirectory are noticed by recursive watch. TestDelegate delegate(this); DirectoryWatcher watcher; - ASSERT_TRUE(watcher.Watch(test_dir_, &delegate, true)); + ASSERT_TRUE(watcher.Watch(test_dir_, &delegate, NULL, true)); // Write a file to the subdir. SetExpectedNumberOfNotifiedDelegates(1); ASSERT_TRUE(WriteTestFile(subdir.AppendASCII("test_file"), "some content")); @@ -244,7 +240,7 @@ TEST_F(DirectoryWatcherTest, SubDirNonRecursive) { // by a not-recursive watch. DirectoryWatcher watcher; TestDelegate delegate(this); - ASSERT_TRUE(watcher.Watch(test_dir_, &delegate, false)); + ASSERT_TRUE(watcher.Watch(test_dir_, &delegate, NULL, false)); // Modify the test file. There should be no notifications. SetExpectedNumberOfNotifiedDelegates(0); @@ -276,7 +272,7 @@ class Deleter : public DirectoryWatcher::Delegate { TEST_F(DirectoryWatcherTest, DeleteDuringNotify) { DirectoryWatcher* watcher = new DirectoryWatcher; Deleter deleter(watcher, &loop_); // Takes ownership of watcher. - ASSERT_TRUE(watcher->Watch(test_dir_, &deleter, false)); + ASSERT_TRUE(watcher->Watch(test_dir_, &deleter, NULL, false)); ASSERT_TRUE(WriteTestFile(test_dir_.AppendASCII("test_file"), "content")); loop_.Run(); @@ -286,11 +282,21 @@ TEST_F(DirectoryWatcherTest, DeleteDuringNotify) { ASSERT_TRUE(deleter.watcher_.get() == NULL); } +TEST_F(DirectoryWatcherTest, BackendLoop) { + base::Thread thread("test"); + ASSERT_TRUE(thread.Start()); + + DirectoryWatcher watcher; + TestDelegate delegate(this); + ASSERT_TRUE(watcher.Watch(test_dir_, &delegate, thread.message_loop(), + true)); +} + TEST_F(DirectoryWatcherTest, MultipleWatchersSingleFile) { DirectoryWatcher watcher1, watcher2; TestDelegate delegate1(this), delegate2(this); - ASSERT_TRUE(watcher1.Watch(test_dir_, &delegate1, false)); - ASSERT_TRUE(watcher2.Watch(test_dir_, &delegate2, false)); + ASSERT_TRUE(watcher1.Watch(test_dir_, &delegate1, NULL, false)); + ASSERT_TRUE(watcher2.Watch(test_dir_, &delegate2, NULL, false)); SetExpectedNumberOfNotifiedDelegates(2); ASSERT_TRUE(WriteTestFile(test_dir_.AppendASCII("test_file"), "content")); @@ -304,7 +310,8 @@ TEST_F(DirectoryWatcherTest, MultipleWatchersDifferentFiles) { FilePath subdirs[kNumberOfWatchers]; for (int i = 0; i < kNumberOfWatchers; i++) { subdirs[i] = CreateTestDirDirectoryASCII("Dir" + IntToString(i), false); - ASSERT_TRUE(watchers[i].Watch(subdirs[i], &delegates[i], false)); + ASSERT_TRUE(watchers[i].Watch(subdirs[i], &delegates[i], + NULL, ((i % 2) == 0))); } for (int i = 0; i < kNumberOfWatchers; i++) { // Verify that we only get modifications from one watcher (each watcher has @@ -328,7 +335,7 @@ TEST_F(DirectoryWatcherTest, MultipleWatchersDifferentFiles) { TEST_F(DirectoryWatcherTest, WatchCreatedDirectory) { TestDelegate delegate(this); DirectoryWatcher watcher; - ASSERT_TRUE(watcher.Watch(test_dir_, &delegate, true)); + ASSERT_TRUE(watcher.Watch(test_dir_, &delegate, NULL, true)); SetExpectedNumberOfNotifiedDelegates(1); FilePath subdir(CreateTestDirDirectoryASCII("SubDir", true)); @@ -347,7 +354,7 @@ TEST_F(DirectoryWatcherTest, RecursiveWatchDeletedSubdirectory) { TestDelegate delegate(this); DirectoryWatcher watcher; - ASSERT_TRUE(watcher.Watch(test_dir_, &delegate, true)); + ASSERT_TRUE(watcher.Watch(test_dir_, &delegate, NULL, true)); // Write a file to the subdir. SetExpectedNumberOfNotifiedDelegates(1); @@ -367,8 +374,8 @@ TEST_F(DirectoryWatcherTest, MoveFileAcrossWatches) { TestDelegate delegate1(this), delegate2(this); DirectoryWatcher watcher1, watcher2; - ASSERT_TRUE(watcher1.Watch(subdir1, &delegate1, true)); - ASSERT_TRUE(watcher2.Watch(subdir2, &delegate2, true)); + ASSERT_TRUE(watcher1.Watch(subdir1, &delegate1, NULL, true)); + ASSERT_TRUE(watcher2.Watch(subdir2, &delegate2, NULL, true)); SetExpectedNumberOfNotifiedDelegates(1); ASSERT_TRUE(WriteTestFile(subdir1.AppendASCII("file"), "some content")); @@ -397,8 +404,8 @@ TEST_F(DirectoryWatcherTest, MoveFileAcrossWatches) { // Basic test: add a file and verify we notice it. TEST_F(DirectoryWatcherTest, NonExistentDirectory) { DirectoryWatcher watcher; - ASSERT_FALSE(watcher.Watch(test_dir_.AppendASCII("does-not-exist"), NULL, - false)); + ASSERT_FALSE(watcher.Watch(test_dir_.AppendASCII("does-not-exist"), + NULL, NULL, false)); } } // namespace diff --git a/base/directory_watcher_win.cc b/base/directory_watcher_win.cc index e75fe57..b6eb9ab 100644 --- a/base/directory_watcher_win.cc +++ b/base/directory_watcher_win.cc @@ -18,7 +18,7 @@ class DirectoryWatcherImpl : public DirectoryWatcher::PlatformDelegate, virtual ~DirectoryWatcherImpl(); virtual bool Watch(const FilePath& path, DirectoryWatcher::Delegate* delegate, - bool recursive); + MessageLoop* backend_loop, bool recursive); // Callback from MessageLoopForIO. virtual void OnObjectSignaled(HANDLE object); @@ -44,7 +44,8 @@ DirectoryWatcherImpl::~DirectoryWatcherImpl() { } bool DirectoryWatcherImpl::Watch(const FilePath& path, - DirectoryWatcher::Delegate* delegate, bool recursive) { + DirectoryWatcher::Delegate* delegate, + MessageLoop* backend_loop, bool recursive) { DCHECK(path_.value().empty()); // Can only watch one path. handle_ = FindFirstChangeNotification( diff --git a/base/file_util.h b/base/file_util.h index 3d07229..a3c9a6e 100644 --- a/base/file_util.h +++ b/base/file_util.h @@ -15,6 +15,7 @@ #elif defined(OS_POSIX) #include <fts.h> #include <sys/stat.h> +#include <sys/types.h> #endif #include <stdio.h> @@ -342,6 +343,11 @@ bool GetFileInfo(const FilePath& file_path, FileInfo* info); // Deprecated temporary compatibility function. bool GetFileInfo(const std::wstring& file_path, FileInfo* info); +#if defined(OS_POSIX) +// Store inode number of |path| in |inode|. Return true on success. +bool GetInode(const FilePath& path, ino_t* inode); +#endif + // Wrapper for fopen-like calls. Returns non-NULL FILE* on success. FILE* OpenFile(const FilePath& filename, const char* mode); // Deprecated temporary compatibility functions. diff --git a/base/file_util_posix.cc b/base/file_util_posix.cc index ae296ca..96c1c17 100644 --- a/base/file_util_posix.cc +++ b/base/file_util_posix.cc @@ -440,6 +440,16 @@ bool GetFileInfo(const FilePath& file_path, FileInfo* results) { return true; } +bool GetInode(const FilePath& path, ino_t* inode) { + struct stat buffer; + int result = stat(path.value().c_str(), &buffer); + if (result < 0) + return false; + + *inode = buffer.st_ino; + return true; +} + FILE* OpenFile(const std::string& filename, const char* mode) { return OpenFile(FilePath(filename), mode); } |