15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/files/file_path_watcher.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <errno.h>
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <string.h>
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <sys/inotify.h>
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <sys/ioctl.h>
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <sys/select.h>
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <unistd.h>
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <algorithm>
15cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include <map>
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <set>
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <utility>
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <vector>
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h"
217d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "base/containers/hash_tables.h"
228bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#include "base/debug/trace_event.h"
23cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "base/files/file_enumerator.h"
242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/files/file_path.h"
256e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include "base/files/file_util.h"
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/lazy_instance.h"
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/location.h"
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h"
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/memory/scoped_ptr.h"
30ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch#include "base/message_loop/message_loop.h"
31868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/message_loop/message_loop_proxy.h"
322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/posix/eintr_wrapper.h"
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/synchronization/lock.h"
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/threading/thread.h"
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace base {
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class FilePathWatcherImpl;
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Singleton to manage all inotify watches.
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// TODO(tony): It would be nice if this wasn't a singleton.
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// http://crbug.com/38174
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class InotifyReader {
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  typedef int Watch;  // Watch descriptor used by AddWatch and RemoveWatch.
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static const Watch kInvalidWatch = -1;
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Watch directory |path| for changes. |watcher| will be notified on each
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // change. Returns kInvalidWatch on failure.
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Watch AddWatch(const FilePath& path, FilePathWatcherImpl* watcher);
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
545c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  // Remove |watch| if it's valid.
555c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  void RemoveWatch(Watch watch, FilePathWatcherImpl* watcher);
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Callback for InotifyReaderTask.
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void OnInotifyEvent(const inotify_event* event);
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
61f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  friend struct DefaultLazyInstanceTraits<InotifyReader>;
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  typedef std::set<FilePathWatcherImpl*> WatcherSet;
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  InotifyReader();
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ~InotifyReader();
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We keep track of which delegates want to be notified on which watches.
69f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  hash_map<Watch, WatcherSet> watchers_;
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Lock to protect watchers_.
72f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  Lock lock_;
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Separate thread on which we run blocking read for inotify events.
75f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  Thread thread_;
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // File descriptor returned by inotify_init.
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const int inotify_fd_;
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Use self-pipe trick to unblock select during shutdown.
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int shutdown_pipe_[2];
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Flag set to true when startup was successful.
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool valid_;
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(InotifyReader);
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class FilePathWatcherImpl : public FilePathWatcher::PlatformDelegate,
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            public MessageLoop::DestructionObserver {
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  FilePathWatcherImpl();
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Called for each event coming from the watch. |fired_watch| identifies the
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // watch that fired, |child| indicates what has changed, and is relative to
96cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // the currently watched path for |fired_watch|.
97cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  //
98cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // |created| is true if the object appears.
99cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // |deleted| is true if the object disappears.
100cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // |is_dir| is true if the object is a directory.
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void OnFilePathChanged(InotifyReader::Watch fired_watch,
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         const FilePath::StringType& child,
103cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                         bool created,
104cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                         bool deleted,
105cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                         bool is_dir);
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1075c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu protected:
1085c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  virtual ~FilePathWatcherImpl() {}
1095c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
1105c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu private:
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Start watching |path| for changes and notify |delegate| on each change.
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Returns true if watch for |path| has been added successfully.
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual bool Watch(const FilePath& path,
1142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                     bool recursive,
1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                     const FilePathWatcher::Callback& callback) OVERRIDE;
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Cancel the watch. This unregisters the instance with InotifyReader.
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void Cancel() OVERRIDE;
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1205c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  // Cleans up and stops observing the message_loop() thread.
1215c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  virtual void CancelOnMessageLoopThread() OVERRIDE;
1225c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Deletion of the FilePathWatcher will call Cancel() to dispose of this
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // object in the right thread. This also observes destruction of the required
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // cleanup thread, in case it quits before Cancel() is called.
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void WillDestroyCurrentMessageLoop() OVERRIDE;
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Inotify watches are installed for all directory components of |target_|. A
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // WatchEntry instance holds the watch descriptor for a component and the
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // subdirectory for that identifies the next component. If a symbolic link
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // is being watched, the target of the link is also kept.
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  struct WatchEntry {
1335c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    explicit WatchEntry(const FilePath::StringType& dirname)
1345c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu        : watch(InotifyReader::kInvalidWatch),
1355c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu          subdir(dirname) {}
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1375c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    InotifyReader::Watch watch;
1385c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    FilePath::StringType subdir;
1395c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    FilePath::StringType linkname;
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  };
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  typedef std::vector<WatchEntry> WatchVector;
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Reconfigure to watch for the most specific parent directory of |target_|
144cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // that exists. Also calls UpdateRecursiveWatches() below.
145cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  void UpdateWatches();
146cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
147cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // Reconfigure to recursively watch |target_| and all its sub-directories.
148cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // - This is a no-op if the watch is not recursive.
149cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // - If |target_| does not exist, then clear all the recursive watches.
150cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // - Assuming |target_| exists, passing kInvalidWatch as |fired_watch| forces
151cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  //   addition of recursive watches for |target_|.
152cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // - Otherwise, only the directory associated with |fired_watch| and its
153cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  //   sub-directories will be reconfigured.
154cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  void UpdateRecursiveWatches(InotifyReader::Watch fired_watch, bool is_dir);
155cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
156cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // Enumerate recursively through |path| and add / update watches.
157cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  void UpdateRecursiveWatchesForPath(const FilePath& path);
158cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
159cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // Do internal bookkeeping to update mappings between |watch| and its
160cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // associated full path |path|.
161cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  void TrackWatchForRecursion(InotifyReader::Watch watch, const FilePath& path);
162cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
163cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // Remove all the recursive watches.
164cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  void RemoveRecursiveWatches();
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1665c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  // |path| is a symlink to a non-existent target. Attempt to add a watch to
1675c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  // the link target's parent directory. Returns true and update |watch_entry|
1685c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  // on success.
1695c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  bool AddWatchForBrokenSymlink(const FilePath& path, WatchEntry* watch_entry);
1705c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
1715c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  bool HasValidWatchVector() const;
1725c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
1732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Callback to notify upon changes.
1742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  FilePathWatcher::Callback callback_;
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The file or directory we're supposed to watch.
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  FilePath target_;
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
179cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  bool recursive_;
180cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The vector of watches and next component names for all path components,
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // starting at the root directory. The last entry corresponds to the watch for
1835c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  // |target_| and always stores an empty next component name in |subdir|.
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  WatchVector watches_;
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
186cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  hash_map<InotifyReader::Watch, FilePath> recursive_paths_by_watch_;
187cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  std::map<FilePath, InotifyReader::Watch> recursive_watches_by_path_;
188cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(FilePathWatcherImpl);
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void InotifyReaderCallback(InotifyReader* reader, int inotify_fd,
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           int shutdown_fd) {
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Make sure the file descriptors are good for use with select().
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK_LE(0, inotify_fd);
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK_GT(FD_SETSIZE, inotify_fd);
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK_LE(0, shutdown_fd);
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK_GT(FD_SETSIZE, shutdown_fd);
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
200f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  debug::TraceLog::GetInstance()->SetCurrentThreadBlocksMessageLoop();
2018bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while (true) {
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    fd_set rfds;
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    FD_ZERO(&rfds);
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    FD_SET(inotify_fd, &rfds);
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    FD_SET(shutdown_fd, &rfds);
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Wait until some inotify events are available.
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int select_result =
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      HANDLE_EINTR(select(std::max(inotify_fd, shutdown_fd) + 1,
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          &rfds, NULL, NULL, NULL));
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (select_result < 0) {
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      DPLOG(WARNING) << "select failed";
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (FD_ISSET(shutdown_fd, &rfds))
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Adjust buffer size to current event queue size.
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int buffer_size;
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int ioctl_result = HANDLE_EINTR(ioctl(inotify_fd, FIONREAD,
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                          &buffer_size));
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (ioctl_result != 0) {
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      DPLOG(WARNING) << "ioctl failed";
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::vector<char> buffer(buffer_size);
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ssize_t bytes_read = HANDLE_EINTR(read(inotify_fd, &buffer[0],
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                           buffer_size));
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (bytes_read < 0) {
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      DPLOG(WARNING) << "read from inotify fd failed";
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ssize_t i = 0;
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    while (i < bytes_read) {
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      inotify_event* event = reinterpret_cast<inotify_event*>(&buffer[i]);
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      size_t event_size = sizeof(inotify_event) + event->len;
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      DCHECK(i + event_size <= static_cast<size_t>(bytes_read));
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      reader->OnInotifyEvent(event);
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      i += event_size;
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
251f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)static LazyInstance<InotifyReader>::Leaky g_inotify_reader =
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LAZY_INSTANCE_INITIALIZER;
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)InotifyReader::InotifyReader()
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : thread_("inotify_reader"),
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      inotify_fd_(inotify_init()),
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      valid_(false) {
258f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (inotify_fd_ < 0)
259f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    PLOG(ERROR) << "inotify_init() failed";
260f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  shutdown_pipe_[0] = -1;
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  shutdown_pipe_[1] = -1;
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (inotify_fd_ >= 0 && pipe(shutdown_pipe_) == 0 && thread_.Start()) {
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    thread_.message_loop()->PostTask(
2655c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu        FROM_HERE,
2665c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu        Bind(&InotifyReaderCallback, this, inotify_fd_, shutdown_pipe_[0]));
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    valid_ = true;
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)InotifyReader::~InotifyReader() {
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (valid_) {
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Write to the self-pipe so that the select call in InotifyReaderTask
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // returns.
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ssize_t ret = HANDLE_EINTR(write(shutdown_pipe_[1], "", 1));
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DPCHECK(ret > 0);
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK_EQ(ret, 1);
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    thread_.Stop();
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (inotify_fd_ >= 0)
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    close(inotify_fd_);
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (shutdown_pipe_[0] >= 0)
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    close(shutdown_pipe_[0]);
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (shutdown_pipe_[1] >= 0)
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    close(shutdown_pipe_[1]);
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)InotifyReader::Watch InotifyReader::AddWatch(
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const FilePath& path, FilePathWatcherImpl* watcher) {
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!valid_)
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return kInvalidWatch;
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
293f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  AutoLock auto_lock(lock_);
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Watch watch = inotify_add_watch(inotify_fd_, path.value().c_str(),
296cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                                  IN_ATTRIB | IN_CREATE | IN_DELETE |
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                  IN_CLOSE_WRITE | IN_MOVE |
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                  IN_ONLYDIR);
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (watch == kInvalidWatch)
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return kInvalidWatch;
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  watchers_[watch].insert(watcher);
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return watch;
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3085c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liuvoid InotifyReader::RemoveWatch(Watch watch, FilePathWatcherImpl* watcher) {
3095c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  if (!valid_ || (watch == kInvalidWatch))
3105c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    return;
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
312f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  AutoLock auto_lock(lock_);
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  watchers_[watch].erase(watcher);
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (watchers_[watch].empty()) {
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    watchers_.erase(watch);
3185c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    inotify_rm_watch(inotify_fd_, watch);
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void InotifyReader::OnInotifyEvent(const inotify_event* event) {
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (event->mask & IN_IGNORED)
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  FilePath::StringType child(event->len ? event->name : FILE_PATH_LITERAL(""));
327f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  AutoLock auto_lock(lock_);
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (WatcherSet::iterator watcher = watchers_[event->wd].begin();
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       watcher != watchers_[event->wd].end();
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       ++watcher) {
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    (*watcher)->OnFilePathChanged(event->wd,
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                  child,
334cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                                  event->mask & (IN_CREATE | IN_MOVED_TO),
335cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                                  event->mask & (IN_DELETE | IN_MOVED_FROM),
336cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                                  event->mask & IN_ISDIR);
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
340cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)FilePathWatcherImpl::FilePathWatcherImpl()
341cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    : recursive_(false) {
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void FilePathWatcherImpl::OnFilePathChanged(InotifyReader::Watch fired_watch,
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                            const FilePath::StringType& child,
346cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                                            bool created,
347cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                                            bool deleted,
348cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                                            bool is_dir) {
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!message_loop()->BelongsToCurrentThread()) {
3505c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    // Switch to message_loop() to access |watches_| safely.
3515c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    message_loop()->PostTask(
3525c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu        FROM_HERE,
3535c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu        Bind(&FilePathWatcherImpl::OnFilePathChanged, this,
354cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)             fired_watch, child, created, deleted, is_dir));
3555c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    return;
3565c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  }
3575c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
3585c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  // Check to see if CancelOnMessageLoopThread() has already been called.
3595c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  // May happen when code flow reaches here from the PostTask() above.
3605c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  if (watches_.empty()) {
3615c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    DCHECK(target_.empty());
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(MessageLoopForIO::current());
3665c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  DCHECK(HasValidWatchVector());
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
368cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // Used below to avoid multiple recursive updates.
369cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  bool did_update = false;
370cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Find the entry in |watches_| that corresponds to |fired_watch|.
3725c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  for (size_t i = 0; i < watches_.size(); ++i) {
3735c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    const WatchEntry& watch_entry = watches_[i];
3745c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    if (fired_watch != watch_entry.watch)
3755c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      continue;
3765c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
3775c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    // Check whether a path component of |target_| changed.
3785c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    bool change_on_target_path =
3795c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu        child.empty() ||
3805c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu        (child == watch_entry.linkname) ||
3815c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu        (child == watch_entry.subdir);
3825c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
3835c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    // Check if the change references |target_| or a direct child of |target_|.
3845c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    bool is_watch_for_target = watch_entry.subdir.empty();
3855c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    bool target_changed =
3865c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu        (is_watch_for_target && (child == watch_entry.linkname)) ||
3875c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu        (is_watch_for_target && watch_entry.linkname.empty()) ||
3885c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu        (watch_entry.subdir == child && watches_[i + 1].subdir.empty());
3895c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
3905c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    // Update watches if a directory component of the |target_| path
3915c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    // (dis)appears. Note that we don't add the additional restriction of
3925c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    // checking the event mask to see if it is for a directory here as changes
3935c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    // to symlinks on the target path will not have IN_ISDIR set in the event
3945c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    // masks. As a result we may sometimes call UpdateWatches() unnecessarily.
395cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    if (change_on_target_path && (created || deleted) && !did_update) {
396cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      UpdateWatches();
397cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      did_update = true;
3985c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    }
3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4005c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    // Report the following events:
4015c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    //  - The target or a direct child of the target got changed (in case the
4025c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    //    watched path refers to a directory).
4035c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    //  - One of the parent directories got moved or deleted, since the target
4045c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    //    disappears in this case.
4055c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    //  - One of the parent directories appears. The event corresponding to
4065c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    //    the target appearing might have been missed in this case, so recheck.
4075c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    if (target_changed ||
408cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        (change_on_target_path && deleted) ||
409cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        (change_on_target_path && created && PathExists(target_))) {
410cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      if (!did_update) {
411cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        UpdateRecursiveWatches(fired_watch, is_dir);
412cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        did_update = true;
413cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      }
4145c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      callback_.Run(target_, false /* error */);
4155c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      return;
4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
418cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
419cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (ContainsKey(recursive_paths_by_watch_, fired_watch)) {
420cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    if (!did_update)
421cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      UpdateRecursiveWatches(fired_watch, is_dir);
422cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    callback_.Run(target_, false /* error */);
423cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool FilePathWatcherImpl::Watch(const FilePath& path,
4272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                bool recursive,
4282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                const FilePathWatcher::Callback& callback) {
4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(target_.empty());
4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(MessageLoopForIO::current());
4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4321320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  set_message_loop(MessageLoopProxy::current());
4332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  callback_ = callback;
4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  target_ = path;
435cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  recursive_ = recursive;
4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  MessageLoop::current()->AddDestructionObserver(this);
4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<FilePath::StringType> comps;
4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  target_.GetComponents(&comps);
4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!comps.empty());
4415c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  for (size_t i = 1; i < comps.size(); ++i)
4425c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    watches_.push_back(WatchEntry(comps[i]));
4435c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  watches_.push_back(WatchEntry(FilePath::StringType()));
444cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  UpdateWatches();
445cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  return true;
4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void FilePathWatcherImpl::Cancel() {
4492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (callback_.is_null()) {
4505c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    // Watch was never called, or the message_loop() thread is already gone.
4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    set_cancelled();
4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4555c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  // Switch to the message_loop() if necessary so we can access |watches_|.
4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!message_loop()->BelongsToCurrentThread()) {
4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    message_loop()->PostTask(FROM_HERE,
458f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                             Bind(&FilePathWatcher::CancelWatch,
4595c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu                                  make_scoped_refptr(this)));
4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CancelOnMessageLoopThread();
4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void FilePathWatcherImpl::CancelOnMessageLoopThread() {
466f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  DCHECK(message_loop()->BelongsToCurrentThread());
4675c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  set_cancelled();
4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!callback_.is_null()) {
4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    MessageLoop::current()->RemoveDestructionObserver(this);
4712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    callback_.Reset();
4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4745c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  for (size_t i = 0; i < watches_.size(); ++i)
4755c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    g_inotify_reader.Get().RemoveWatch(watches_[i].watch, this);
4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  watches_.clear();
4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  target_.clear();
478cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
479cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (recursive_)
480cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    RemoveRecursiveWatches();
4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void FilePathWatcherImpl::WillDestroyCurrentMessageLoop() {
4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CancelOnMessageLoopThread();
4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
487cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void FilePathWatcherImpl::UpdateWatches() {
4885c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  // Ensure this runs on the message_loop() exclusively in order to avoid
4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // concurrency issues.
4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(message_loop()->BelongsToCurrentThread());
4915c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  DCHECK(HasValidWatchVector());
4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Walk the list of watches and update them as we go.
4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  FilePath path(FILE_PATH_LITERAL("/"));
4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool path_valid = true;
4965c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  for (size_t i = 0; i < watches_.size(); ++i) {
4975c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    WatchEntry& watch_entry = watches_[i];
4985c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    InotifyReader::Watch old_watch = watch_entry.watch;
4995c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    watch_entry.watch = InotifyReader::kInvalidWatch;
5005c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    watch_entry.linkname.clear();
5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (path_valid) {
5025c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      watch_entry.watch = g_inotify_reader.Get().AddWatch(path, this);
5035c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      if (watch_entry.watch == InotifyReader::kInvalidWatch) {
5045c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu        if (IsLink(path)) {
5055c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu          path_valid = AddWatchForBrokenSymlink(path, &watch_entry);
5065c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu        } else {
5075c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu          path_valid = false;
5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
5115c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    if (old_watch != watch_entry.watch)
5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      g_inotify_reader.Get().RemoveWatch(old_watch, this);
5135c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    path = path.Append(watch_entry.subdir);
5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
516cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  UpdateRecursiveWatches(InotifyReader::kInvalidWatch,
517cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                         false /* is directory? */);
518cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
519cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
520cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void FilePathWatcherImpl::UpdateRecursiveWatches(
521cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    InotifyReader::Watch fired_watch,
522cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    bool is_dir) {
523cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (!recursive_)
524cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return;
525cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
526cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (!DirectoryExists(target_)) {
527cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    RemoveRecursiveWatches();
528cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return;
529cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
530cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
531cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // Check to see if this is a forced update or if some component of |target_|
532cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // has changed. For these cases, redo the watches for |target_| and below.
533cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (!ContainsKey(recursive_paths_by_watch_, fired_watch)) {
534cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    UpdateRecursiveWatchesForPath(target_);
535cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return;
536cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
537cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
538cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // Underneath |target_|, only directory changes trigger watch updates.
539cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (!is_dir)
540cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return;
541cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
542cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  const FilePath& changed_dir = recursive_paths_by_watch_[fired_watch];
543cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
544cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  std::map<FilePath, InotifyReader::Watch>::iterator start_it =
545cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      recursive_watches_by_path_.lower_bound(changed_dir);
546cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  std::map<FilePath, InotifyReader::Watch>::iterator end_it = start_it;
547cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  for (; end_it != recursive_watches_by_path_.end(); ++end_it) {
548cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    const FilePath& cur_path = end_it->first;
549cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    if (!changed_dir.IsParent(cur_path))
550cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      break;
551cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    if (!DirectoryExists(cur_path))
552cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      g_inotify_reader.Get().RemoveWatch(end_it->second, this);
553cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
554cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  recursive_watches_by_path_.erase(start_it, end_it);
555cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  UpdateRecursiveWatchesForPath(changed_dir);
556cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
557cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
558cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void FilePathWatcherImpl::UpdateRecursiveWatchesForPath(const FilePath& path) {
559cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  DCHECK(recursive_);
560cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  DCHECK(!path.empty());
561cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  DCHECK(DirectoryExists(path));
562cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
563cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // Note: SHOW_SYM_LINKS exposes symlinks as symlinks, so they are ignored
564cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // rather than followed. Following symlinks can easily lead to the undesirable
565cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // situation where the entire file system is being watched.
566cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  FileEnumerator enumerator(
567cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      path,
568cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      true /* recursive enumeration */,
569cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      FileEnumerator::DIRECTORIES | FileEnumerator::SHOW_SYM_LINKS);
570cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  for (FilePath current = enumerator.Next();
571cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)       !current.empty();
572cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)       current = enumerator.Next()) {
573cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    DCHECK(enumerator.GetInfo().IsDirectory());
574cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
575cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    if (!ContainsKey(recursive_watches_by_path_, current)) {
576cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      // Add new watches.
577cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      InotifyReader::Watch watch =
578cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          g_inotify_reader.Get().AddWatch(current, this);
579cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      TrackWatchForRecursion(watch, current);
580cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    } else {
581cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      // Update existing watches.
582cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      InotifyReader::Watch old_watch = recursive_watches_by_path_[current];
583cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      DCHECK_NE(InotifyReader::kInvalidWatch, old_watch);
584cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      InotifyReader::Watch watch =
585cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          g_inotify_reader.Get().AddWatch(current, this);
586cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      if (watch != old_watch) {
587cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        g_inotify_reader.Get().RemoveWatch(old_watch, this);
588cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        recursive_paths_by_watch_.erase(old_watch);
589cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        recursive_watches_by_path_.erase(current);
590cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        TrackWatchForRecursion(watch, current);
591cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      }
592cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    }
593cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
594cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
595cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
596cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void FilePathWatcherImpl::TrackWatchForRecursion(InotifyReader::Watch watch,
597cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                                                 const FilePath& path) {
598cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  DCHECK(recursive_);
599cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  DCHECK(!path.empty());
600cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  DCHECK(target_.IsParent(path));
601cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
602cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (watch == InotifyReader::kInvalidWatch)
603cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return;
604cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
605cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  DCHECK(!ContainsKey(recursive_paths_by_watch_, watch));
606cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  DCHECK(!ContainsKey(recursive_watches_by_path_, path));
607cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  recursive_paths_by_watch_[watch] = path;
608cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  recursive_watches_by_path_[path] = watch;
609cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
610cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
611cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void FilePathWatcherImpl::RemoveRecursiveWatches() {
612cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (!recursive_)
613cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return;
614cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
615cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  for (hash_map<InotifyReader::Watch, FilePath>::const_iterator it =
616cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)           recursive_paths_by_watch_.begin();
617cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)       it != recursive_paths_by_watch_.end();
618cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)       ++it) {
619cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    g_inotify_reader.Get().RemoveWatch(it->first, this);
620cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
621cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  recursive_paths_by_watch_.clear();
622cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  recursive_watches_by_path_.clear();
6235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6255c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liubool FilePathWatcherImpl::AddWatchForBrokenSymlink(const FilePath& path,
6265c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu                                                   WatchEntry* watch_entry) {
6275c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  DCHECK_EQ(InotifyReader::kInvalidWatch, watch_entry->watch);
6285c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  FilePath link;
6295c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  if (!ReadSymbolicLink(path, &link))
6305c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    return false;
6315c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
6325c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  if (!link.IsAbsolute())
6335c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    link = path.DirName().Append(link);
6345c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
6355c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  // Try watching symlink target directory. If the link target is "/", then we
6365c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  // shouldn't get here in normal situations and if we do, we'd watch "/" for
6375c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  // changes to a component "/" which is harmless so no special treatment of
6385c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  // this case is required.
6395c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  InotifyReader::Watch watch =
6405c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      g_inotify_reader.Get().AddWatch(link.DirName(), this);
6415c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  if (watch == InotifyReader::kInvalidWatch) {
6425c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    // TODO(craig) Symlinks only work if the parent directory for the target
6435c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    // exist. Ideally we should make sure we've watched all the components of
6445c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    // the symlink path for changes. See crbug.com/91561 for details.
6455c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    DPLOG(WARNING) << "Watch failed for "  << link.DirName().value();
6465c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    return false;
6475c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  }
6485c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  watch_entry->watch = watch;
6495c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  watch_entry->linkname = link.BaseName().value();
6505c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  return true;
6515c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}
6525c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
6535c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liubool FilePathWatcherImpl::HasValidWatchVector() const {
6545c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  if (watches_.empty())
6555c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    return false;
6565c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  for (size_t i = 0; i < watches_.size() - 1; ++i) {
6575c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    if (watches_[i].subdir.empty())
6585c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      return false;
6595c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  }
6605c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  return watches_[watches_.size() - 1].subdir.empty();
6615c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}
6625c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
6635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
6645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)FilePathWatcher::FilePathWatcher() {
6665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  impl_ = new FilePathWatcherImpl();
6675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace base
670