1ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved. 23345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick// Use of this source code is governed by a BSD-style license that can be 33345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick// found in the LICENSE file. 43345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 5ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "base/files/file_path_watcher.h" 63345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 73345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include <errno.h> 83345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include <string.h> 93345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include <sys/inotify.h> 103345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include <sys/ioctl.h> 113345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include <sys/select.h> 123345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include <unistd.h> 133345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 143345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include <algorithm> 153345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include <set> 163345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include <utility> 173345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include <vector> 183345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 193345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "base/eintr_wrapper.h" 203345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "base/file_path.h" 213345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "base/file_util.h" 223345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "base/hash_tables.h" 2321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "base/lazy_instance.h" 243345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "base/logging.h" 25ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "base/memory/scoped_ptr.h" 263345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "base/message_loop.h" 27ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "base/message_loop_proxy.h" 2872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "base/synchronization/lock.h" 293345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "base/task.h" 303f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen#include "base/threading/thread.h" 313345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 32ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsennamespace base { 33ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsennamespace files { 34ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 353345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merricknamespace { 363345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 373345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickclass FilePathWatcherImpl; 383345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 393345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick// Singleton to manage all inotify watches. 403345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick// TODO(tony): It would be nice if this wasn't a singleton. 413345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick// http://crbug.com/38174 423345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickclass InotifyReader { 433345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick public: 443345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick typedef int Watch; // Watch descriptor used by AddWatch and RemoveWatch. 453345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick static const Watch kInvalidWatch = -1; 463345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 473345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // Watch directory |path| for changes. |watcher| will be notified on each 483345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // change. Returns kInvalidWatch on failure. 493345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick Watch AddWatch(const FilePath& path, FilePathWatcherImpl* watcher); 503345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 513345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // Remove |watch|. Returns true on success. 523345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick bool RemoveWatch(Watch watch, FilePathWatcherImpl* watcher); 533345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 543345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // Callback for InotifyReaderTask. 553345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick void OnInotifyEvent(const inotify_event* event); 563345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 573345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick private: 5821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen friend struct ::base::DefaultLazyInstanceTraits<InotifyReader>; 593345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 603345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick typedef std::set<FilePathWatcherImpl*> WatcherSet; 613345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 623345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick InotifyReader(); 633345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick ~InotifyReader(); 643345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 653345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // We keep track of which delegates want to be notified on which watches. 663345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick base::hash_map<Watch, WatcherSet> watchers_; 673345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 683345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // Lock to protect watchers_. 6972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen base::Lock lock_; 703345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 713345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // Separate thread on which we run blocking read for inotify events. 723345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick base::Thread thread_; 733345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 743345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // File descriptor returned by inotify_init. 753345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick const int inotify_fd_; 763345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 773345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // Use self-pipe trick to unblock select during shutdown. 783345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick int shutdown_pipe_[2]; 793345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 803345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // Flag set to true when startup was successful. 813345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick bool valid_; 823345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 833345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick DISALLOW_COPY_AND_ASSIGN(InotifyReader); 843345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}; 853345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 86ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenclass FilePathWatcherImpl : public FilePathWatcher::PlatformDelegate, 87ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen public MessageLoop::DestructionObserver { 883345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick public: 893345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick FilePathWatcherImpl(); 903345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 913345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // Called for each event coming from the watch. |fired_watch| identifies the 923345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // watch that fired, |child| indicates what has changed, and is relative to 933345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // the currently watched path for |fired_watch|. The flag |created| is true if 943345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // the object appears, and |is_directory| is set when the event refers to a 953345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // directory. 963345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick void OnFilePathChanged(InotifyReader::Watch fired_watch, 973345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick const FilePath::StringType& child, 983345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick bool created, 993345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick bool is_directory); 1003345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 1013345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // Start watching |path| for changes and notify |delegate| on each change. 1023345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // Returns true if watch for |path| has been added successfully. 103ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen virtual bool Watch(const FilePath& path, 104ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen FilePathWatcher::Delegate* delegate) OVERRIDE; 1053345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 1063345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // Cancel the watch. This unregisters the instance with InotifyReader. 107ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen virtual void Cancel() OVERRIDE; 108ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 109ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // Deletion of the FilePathWatcher will call Cancel() to dispose of this 110ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // object in the right thread. This also observes destruction of the required 111ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // cleanup thread, in case it quits before Cancel() is called. 112ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen virtual void WillDestroyCurrentMessageLoop() OVERRIDE; 1133345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 1143345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick private: 115dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen virtual ~FilePathWatcherImpl() {} 116dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen 117ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // Cleans up and stops observing the |message_loop_| thread. 118ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen void CancelOnMessageLoopThread() OVERRIDE; 119ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 1203345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // Inotify watches are installed for all directory components of |target_|. A 1213345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // WatchEntry instance holds the watch descriptor for a component and the 1223345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // subdirectory for that identifies the next component. 1233345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick struct WatchEntry { 1243345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick WatchEntry(InotifyReader::Watch watch, const FilePath::StringType& subdir) 1253345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick : watch_(watch), 1263345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick subdir_(subdir) {} 1273345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 1283345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick InotifyReader::Watch watch_; 1293345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick FilePath::StringType subdir_; 1303345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick }; 1313345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick typedef std::vector<WatchEntry> WatchVector; 1323345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 1333345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // Reconfigure to watch for the most specific parent directory of |target_| 1343345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // that exists. Updates |watched_path_|. Returns true on success. 1353345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick bool UpdateWatches() WARN_UNUSED_RESULT; 1363345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 1373345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // Delegate to notify upon changes. 1383345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick scoped_refptr<FilePathWatcher::Delegate> delegate_; 1393345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 1403345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // The file or directory we're supposed to watch. 1413345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick FilePath target_; 1423345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 1433345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // The vector of watches and next component names for all path components, 1443345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // starting at the root directory. The last entry corresponds to the watch for 1453345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // |target_| and always stores an empty next component name in |subdir_|. 1463345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick WatchVector watches_; 1473345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 1483345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick DISALLOW_COPY_AND_ASSIGN(FilePathWatcherImpl); 1493345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}; 1503345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 1513345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickclass InotifyReaderTask : public Task { 1523345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick public: 1533345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick InotifyReaderTask(InotifyReader* reader, int inotify_fd, int shutdown_fd) 1543345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick : reader_(reader), 1553345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick inotify_fd_(inotify_fd), 1563345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick shutdown_fd_(shutdown_fd) { 1573345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick } 1583345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 1593345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick virtual void Run() { 1603345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick while (true) { 1613345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick fd_set rfds; 1623345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick FD_ZERO(&rfds); 1633345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick FD_SET(inotify_fd_, &rfds); 1643345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick FD_SET(shutdown_fd_, &rfds); 1653345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 1663345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // Wait until some inotify events are available. 1673345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick int select_result = 1683345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick HANDLE_EINTR(select(std::max(inotify_fd_, shutdown_fd_) + 1, 1693345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick &rfds, NULL, NULL, NULL)); 1703345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (select_result < 0) { 1713345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick DPLOG(WARNING) << "select failed"; 1723345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick return; 1733345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick } 1743345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 1753345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (FD_ISSET(shutdown_fd_, &rfds)) 1763345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick return; 1773345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 1783345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // Adjust buffer size to current event queue size. 1793345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick int buffer_size; 1803345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick int ioctl_result = HANDLE_EINTR(ioctl(inotify_fd_, FIONREAD, 1813345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick &buffer_size)); 1823345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 1833345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (ioctl_result != 0) { 1843345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick DPLOG(WARNING) << "ioctl failed"; 1853345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick return; 1863345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick } 1873345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 1883345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick std::vector<char> buffer(buffer_size); 1893345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 1903345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick ssize_t bytes_read = HANDLE_EINTR(read(inotify_fd_, &buffer[0], 1913345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick buffer_size)); 1923345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 1933345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (bytes_read < 0) { 1943345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick DPLOG(WARNING) << "read from inotify fd failed"; 1953345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick return; 1963345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick } 1973345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 1983345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick ssize_t i = 0; 1993345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick while (i < bytes_read) { 2003345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick inotify_event* event = reinterpret_cast<inotify_event*>(&buffer[i]); 2013345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick size_t event_size = sizeof(inotify_event) + event->len; 2023345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick DCHECK(i + event_size <= static_cast<size_t>(bytes_read)); 2033345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick reader_->OnInotifyEvent(event); 2043345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick i += event_size; 2053345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick } 2063345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick } 2073345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick } 2083345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 2093345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick private: 2103345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick InotifyReader* reader_; 2113345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick int inotify_fd_; 2123345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick int shutdown_fd_; 2133345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 2143345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick DISALLOW_COPY_AND_ASSIGN(InotifyReaderTask); 2153345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}; 2163345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 21721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsenstatic base::LazyInstance<InotifyReader> g_inotify_reader( 21821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen base::LINKER_INITIALIZED); 21921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen 2203345a6884c488ff3a535c2c9acdd33d74b37e311Iain MerrickInotifyReader::InotifyReader() 2213345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick : thread_("inotify_reader"), 2223345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick inotify_fd_(inotify_init()), 2233345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick valid_(false) { 2243345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick shutdown_pipe_[0] = -1; 2253345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick shutdown_pipe_[1] = -1; 2263345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (inotify_fd_ >= 0 && pipe(shutdown_pipe_) == 0 && thread_.Start()) { 2273345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick thread_.message_loop()->PostTask( 2283345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick FROM_HERE, new InotifyReaderTask(this, inotify_fd_, shutdown_pipe_[0])); 2293345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick valid_ = true; 2303345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick } 2313345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick} 2323345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 2333345a6884c488ff3a535c2c9acdd33d74b37e311Iain MerrickInotifyReader::~InotifyReader() { 2343345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (valid_) { 2353345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // Write to the self-pipe so that the select call in InotifyReaderTask 2363345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // returns. 2373345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick ssize_t ret = HANDLE_EINTR(write(shutdown_pipe_[1], "", 1)); 2383345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick DPCHECK(ret > 0); 2393345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick DCHECK_EQ(ret, 1); 2403345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick thread_.Stop(); 2413345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick } 2423345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (inotify_fd_ >= 0) 2433345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick close(inotify_fd_); 2443345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (shutdown_pipe_[0] >= 0) 2453345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick close(shutdown_pipe_[0]); 2463345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (shutdown_pipe_[1] >= 0) 2473345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick close(shutdown_pipe_[1]); 2483345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick} 2493345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 2503345a6884c488ff3a535c2c9acdd33d74b37e311Iain MerrickInotifyReader::Watch InotifyReader::AddWatch( 2513345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick const FilePath& path, FilePathWatcherImpl* watcher) { 2523345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (!valid_) 2533345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick return kInvalidWatch; 2543345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 25572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen base::AutoLock auto_lock(lock_); 2563345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 2573345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick Watch watch = inotify_add_watch(inotify_fd_, path.value().c_str(), 2583345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick IN_CREATE | IN_DELETE | 2593345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick IN_CLOSE_WRITE | IN_MOVE | 2603345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick IN_ONLYDIR); 2613345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 2623345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (watch == kInvalidWatch) 2633345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick return kInvalidWatch; 2643345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 2653345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick watchers_[watch].insert(watcher); 2663345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 2673345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick return watch; 2683345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick} 2693345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 2703345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickbool InotifyReader::RemoveWatch(Watch watch, 2713345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick FilePathWatcherImpl* watcher) { 2723345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (!valid_) 2733345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick return false; 2743345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 27572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen base::AutoLock auto_lock(lock_); 2763345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 2773345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick watchers_[watch].erase(watcher); 2783345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 2793345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (watchers_[watch].empty()) { 2803345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick watchers_.erase(watch); 2813345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick return (inotify_rm_watch(inotify_fd_, watch) == 0); 2823345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick } 2833345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 2843345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick return true; 2853345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick} 2863345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 2873345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid InotifyReader::OnInotifyEvent(const inotify_event* event) { 2883345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (event->mask & IN_IGNORED) 2893345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick return; 2903345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 2913345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick FilePath::StringType child(event->len ? event->name : FILE_PATH_LITERAL("")); 29272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen base::AutoLock auto_lock(lock_); 2933345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 2943345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick for (WatcherSet::iterator watcher = watchers_[event->wd].begin(); 2953345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick watcher != watchers_[event->wd].end(); 2963345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick ++watcher) { 297ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen (*watcher)->OnFilePathChanged(event->wd, 298ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen child, 299ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen event->mask & (IN_CREATE | IN_MOVED_TO), 300ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen event->mask & IN_ISDIR); 3013345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick } 3023345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick} 3033345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 3043345a6884c488ff3a535c2c9acdd33d74b37e311Iain MerrickFilePathWatcherImpl::FilePathWatcherImpl() 3053345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick : delegate_(NULL) { 3063345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick} 3073345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 308ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid FilePathWatcherImpl::OnFilePathChanged( 309ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen InotifyReader::Watch fired_watch, 310ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen const FilePath::StringType& child, 311ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen bool created, 312ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen bool is_directory) { 313ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 314ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (!message_loop()->BelongsToCurrentThread()) { 315ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // Switch to message_loop_ to access watches_ safely. 316ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen message_loop()->PostTask(FROM_HERE, 317ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen NewRunnableMethod(this, 318ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen &FilePathWatcherImpl::OnFilePathChanged, 319ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen fired_watch, 320ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen child, 321ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen created, 322ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen is_directory)); 323ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen return; 324ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } 325ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 326ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen DCHECK(MessageLoopForIO::current()); 3273345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 3283345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // Find the entry in |watches_| that corresponds to |fired_watch|. 3293345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick WatchVector::const_iterator watch_entry(watches_.begin()); 3303345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick for ( ; watch_entry != watches_.end(); ++watch_entry) { 3313345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (fired_watch == watch_entry->watch_) 3323345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick break; 3333345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick } 3343345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 3353345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // If this notification is from a previous generation of watches or the watch 3363345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // has been cancelled (|watches_| is empty then), bail out. 3373345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (watch_entry == watches_.end()) 3383345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick return; 3393345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 3403345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // Check whether a path component of |target_| changed. 3413345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick bool change_on_target_path = child.empty() || child == watch_entry->subdir_; 3423345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 3433345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // Check whether the change references |target_| or a direct child. 3443345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick DCHECK(watch_entry->subdir_.empty() || (watch_entry + 1) != watches_.end()); 3453345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick bool target_changed = watch_entry->subdir_.empty() || 3463345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick (watch_entry->subdir_ == child && (++watch_entry)->subdir_.empty()); 3473345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 3483345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // Update watches if a directory component of the |target_| path (dis)appears. 3493345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (is_directory && change_on_target_path && !UpdateWatches()) { 350ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen delegate_->OnFilePathError(target_); 3513345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick return; 3523345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick } 3533345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 3543345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // Report the following events: 3553345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // - The target or a direct child of the target got changed (in case the 3563345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // watched path refers to a directory). 3573345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // - One of the parent directories got moved or deleted, since the target 3583345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // disappears in this case. 3593345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // - One of the parent directories appears. The event corresponding to the 3603345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // target appearing might have been missed in this case, so recheck. 3613345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (target_changed || 3623345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick (change_on_target_path && !created) || 3633345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick (change_on_target_path && file_util::PathExists(target_))) { 3643345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick delegate_->OnFilePathChanged(target_); 3653345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick } 3663345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick} 3673345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 3683345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickbool FilePathWatcherImpl::Watch(const FilePath& path, 3693345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick FilePathWatcher::Delegate* delegate) { 3703345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick DCHECK(target_.empty()); 371ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen DCHECK(MessageLoopForIO::current()); 3723345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 373ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen set_message_loop(base::MessageLoopProxy::CreateForCurrentThread()); 3743345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick delegate_ = delegate; 3753345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick target_ = path; 376ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen MessageLoop::current()->AddDestructionObserver(this); 377ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 3783345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick std::vector<FilePath::StringType> comps; 3793345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick target_.GetComponents(&comps); 3803345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick DCHECK(!comps.empty()); 3813345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick for (std::vector<FilePath::StringType>::const_iterator comp(++comps.begin()); 3823345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick comp != comps.end(); ++comp) { 3833345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick watches_.push_back(WatchEntry(InotifyReader::kInvalidWatch, *comp)); 3843345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick } 3853345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick watches_.push_back(WatchEntry(InotifyReader::kInvalidWatch, 3863345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick FilePath::StringType())); 3873345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick return UpdateWatches(); 3883345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick} 3893345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 3903345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid FilePathWatcherImpl::Cancel() { 391ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (!delegate_) { 392ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // Watch was never called, or the |message_loop_| thread is already gone. 393ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen set_cancelled(); 3943345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick return; 3953345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick } 3963345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 397ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // Switch to the message_loop_ if necessary so we can access |watches_|. 398ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (!message_loop()->BelongsToCurrentThread()) { 399ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen message_loop()->PostTask(FROM_HERE, 400ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen new FilePathWatcher::CancelTask(this)); 401ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } else { 402ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen CancelOnMessageLoopThread(); 4033345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick } 404ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen} 405ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 406ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid FilePathWatcherImpl::CancelOnMessageLoopThread() { 407ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (!is_cancelled()) { 408ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen set_cancelled(); 409ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen MessageLoop::current()->RemoveDestructionObserver(this); 410ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 411ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen for (WatchVector::iterator watch_entry(watches_.begin()); 412ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen watch_entry != watches_.end(); ++watch_entry) { 413ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (watch_entry->watch_ != InotifyReader::kInvalidWatch) 414ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen g_inotify_reader.Get().RemoveWatch(watch_entry->watch_, this); 415ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } 416ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen watches_.clear(); 417ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen delegate_ = NULL; 418ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen target_.clear(); 419ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } 420ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen} 421ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 422ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid FilePathWatcherImpl::WillDestroyCurrentMessageLoop() { 423ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen CancelOnMessageLoopThread(); 4243345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick} 4253345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 4263345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickbool FilePathWatcherImpl::UpdateWatches() { 427ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // Ensure this runs on the message_loop_ exclusively in order to avoid 4283345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // concurrency issues. 429ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen DCHECK(message_loop()->BelongsToCurrentThread()); 4303345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 4313345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // Walk the list of watches and update them as we go. 4323345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick FilePath path(FILE_PATH_LITERAL("/")); 4333345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick bool path_valid = true; 4343345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick for (WatchVector::iterator watch_entry(watches_.begin()); 4353345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick watch_entry != watches_.end(); ++watch_entry) { 4363345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick InotifyReader::Watch old_watch = watch_entry->watch_; 4373345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (path_valid) { 43821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen watch_entry->watch_ = g_inotify_reader.Get().AddWatch(path, this); 4393345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (watch_entry->watch_ == InotifyReader::kInvalidWatch) { 4403345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick path_valid = false; 4413345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick } 4423345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick } else { 4433345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick watch_entry->watch_ = InotifyReader::kInvalidWatch; 4443345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick } 4453345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (old_watch != InotifyReader::kInvalidWatch && 4463345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick old_watch != watch_entry->watch_) { 44721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen g_inotify_reader.Get().RemoveWatch(old_watch, this); 4483345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick } 4493345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick path = path.Append(watch_entry->subdir_); 4503345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick } 4513345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 4523345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick return true; 4533345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick} 4543345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 4553345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick} // namespace 4563345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 4573345a6884c488ff3a535c2c9acdd33d74b37e311Iain MerrickFilePathWatcher::FilePathWatcher() { 4583345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick impl_ = new FilePathWatcherImpl(); 4593345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick} 460ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 461ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen} // namespace files 462ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen} // namespace base 463