1ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// Use of this source code is governed by a BSD-style license that can be
3ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// found in the LICENSE file.
4ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
5ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "base/files/file_path_watcher.h"
6ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
7ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include <fcntl.h>
8ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include <sys/event.h>
9ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include <sys/param.h>
10ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
11ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include <vector>
12ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
13ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "base/file_util.h"
14ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "base/message_loop.h"
15ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "base/message_loop_proxy.h"
16ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "base/stringprintf.h"
17ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
18ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsennamespace base {
19ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsennamespace files {
20ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
21ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsennamespace {
22ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
23ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// Mac-specific file watcher implementation based on kqueue.
24ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// Originally it was based on FSEvents so that the semantics were equivalent
25ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// on Linux, OSX and Windows where it was able to detect:
26ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// - file creation/deletion/modification in a watched directory
27ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// - file creation/deletion/modification for a watched file
28ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// - modifications to the paths to a watched object that would affect the
29ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen//   object such as renaming/attibute changes etc.
30ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// The FSEvents version did all of the above except handling attribute changes
31ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// to path components. Unfortunately FSEvents appears to have an issue where the
32ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// current implementation (Mac OS X 10.6.7) sometimes drops events and doesn't
33ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// send notifications. See
34ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// http://code.google.com/p/chromium/issues/detail?id=54822#c31 for source that
35ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// will reproduce the problem. FSEvents also required having a CFRunLoop
36ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// backing the thread that it was running on, that caused added complexity
37ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// in the interfaces.
38ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// The kqueue implementation will handle all of the items in the list above
39ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// except for detecting modifications to files in a watched directory. It will
40ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// detect the creation and deletion of files, just not the modification of
41ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// files. It does however detect the attribute changes that the FSEvents impl
42ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// would miss.
43ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenclass FilePathWatcherImpl : public FilePathWatcher::PlatformDelegate,
44ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                            public MessageLoopForIO::Watcher,
45ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                            public MessageLoop::DestructionObserver {
46ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen public:
47ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  FilePathWatcherImpl() : kqueue_(-1) {}
48ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  virtual ~FilePathWatcherImpl() {}
49ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
50ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // MessageLoopForIO::Watcher overrides.
51ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  virtual void OnFileCanReadWithoutBlocking(int fd) OVERRIDE;
52ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  virtual void OnFileCanWriteWithoutBlocking(int fd) OVERRIDE;
53ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
54ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // MessageLoop::DestructionObserver overrides.
55ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  virtual void WillDestroyCurrentMessageLoop() OVERRIDE;
56ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
57ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // FilePathWatcher::PlatformDelegate overrides.
58ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  virtual bool Watch(const FilePath& path,
59ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                     FilePathWatcher::Delegate* delegate) OVERRIDE;
60ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  virtual void Cancel() OVERRIDE;
61ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
62ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen private:
63ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  class EventData {
64ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen   public:
65ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    EventData(const FilePath& path, const FilePath::StringType& subdir)
66ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        : path_(path), subdir_(subdir) { }
67ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    FilePath path_;  // Full path to this item.
68ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    FilePath::StringType subdir_;  // Path to any sub item.
69ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  };
70ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  typedef std::vector<struct kevent> EventVector;
71ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
72ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Can only be called on |io_message_loop_|'s thread.
73ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  virtual void CancelOnMessageLoopThread() OVERRIDE;
74ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
75ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Returns true if the kevent values are error free.
76ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  bool AreKeventValuesValid(struct kevent* kevents, int count);
77ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
78ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Respond to a change of attributes of the path component represented by
79ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // |event|. Sets |target_file_affected| to true if |target_| is affected.
80ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Sets |update_watches| to true if |events_| need to be updated.
81ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  void HandleAttributesChange(const EventVector::iterator& event,
82ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                              bool* target_file_affected,
83ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                              bool* update_watches);
84ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
85ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Respond to a move of deletion of the path component represented by
86ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // |event|. Sets |target_file_affected| to true if |target_| is affected.
87ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Sets |update_watches| to true if |events_| need to be updated.
88ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  void HandleDeleteOrMoveChange(const EventVector::iterator& event,
89ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                bool* target_file_affected,
90ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                bool* update_watches);
91ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
92ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Respond to a creation of an item in the path component represented by
93ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // |event|. Sets |target_file_affected| to true if |target_| is affected.
94ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Sets |update_watches| to true if |events_| need to be updated.
95ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  void HandleCreateItemChange(const EventVector::iterator& event,
96ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                              bool* target_file_affected,
97ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                              bool* update_watches);
98ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
99ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Update |events_| with the current status of the system.
100ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Sets |target_file_affected| to true if |target_| is affected.
101ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Returns false if an error occurs.
102ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  bool UpdateWatches(bool* target_file_affected);
103ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
104ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Fills |events| with one kevent per component in |path|.
105ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Returns the number of valid events created where a valid event is
106ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // defined as one that has a ident (file descriptor) field != -1.
107ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  static int EventsForPath(FilePath path, EventVector *events);
108ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
109ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Release a kevent generated by EventsForPath.
110ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  static void ReleaseEvent(struct kevent& event);
111ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
112ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Returns a file descriptor that will not block the system from deleting
113ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // the file it references.
114ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  static int FileDescriptorForPath(const FilePath& path);
115ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
116ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Closes |*fd| and sets |*fd| to -1.
117ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  static void CloseFileDescriptor(int* fd);
118ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
119ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Returns true if kevent has open file descriptor.
120ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  static bool IsKeventFileDescriptorOpen(const struct kevent& event) {
121ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    return event.ident != static_cast<uintptr_t>(-1);
122ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
123ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
124ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  static EventData* EventDataForKevent(const struct kevent& event) {
125ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    return reinterpret_cast<EventData*>(event.udata);
126ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
127ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
128ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  EventVector events_;
129ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  scoped_refptr<base::MessageLoopProxy> io_message_loop_;
130ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  MessageLoopForIO::FileDescriptorWatcher kqueue_watcher_;
131ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  scoped_refptr<FilePathWatcher::Delegate> delegate_;
132ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  FilePath target_;
133ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  int kqueue_;
134ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
135ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  DISALLOW_COPY_AND_ASSIGN(FilePathWatcherImpl);
136ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen};
137ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
138ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid FilePathWatcherImpl::ReleaseEvent(struct kevent& event) {
139ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  CloseFileDescriptor(reinterpret_cast<int*>(&event.ident));
140ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  EventData* entry = EventDataForKevent(event);
141ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  delete entry;
142ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  event.udata = NULL;
143ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
144ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
145ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenint FilePathWatcherImpl::EventsForPath(FilePath path, EventVector* events) {
146ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  DCHECK(MessageLoopForIO::current());
147ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Make sure that we are working with a clean slate.
148ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  DCHECK(events->empty());
149ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
150ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  std::vector<FilePath::StringType> components;
151ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  path.GetComponents(&components);
152ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
153ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (components.size() < 1) {
154ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    return -1;
155ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
156ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
157ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  int last_existing_entry = 0;
158ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  FilePath built_path;
159ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  bool path_still_exists = true;
160ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  for(std::vector<FilePath::StringType>::iterator i = components.begin();
161ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      i != components.end(); ++i) {
162ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    if (i == components.begin()) {
163ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      built_path = FilePath(*i);
164ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    } else {
165ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      built_path = built_path.Append(*i);
166ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    }
167ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    int fd = -1;
168ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    if (path_still_exists) {
169ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      fd = FileDescriptorForPath(built_path);
170ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      if (fd == -1) {
171ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        path_still_exists = false;
172ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      } else {
173ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        ++last_existing_entry;
174ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      }
175ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    }
176ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    FilePath::StringType subdir = (i != (components.end() - 1)) ? *(i + 1) : "";
177ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    EventData* data = new EventData(built_path, subdir);
178ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    struct kevent event;
179ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    EV_SET(&event, fd, EVFILT_VNODE, (EV_ADD | EV_CLEAR | EV_RECEIPT),
180ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen           (NOTE_DELETE | NOTE_WRITE | NOTE_ATTRIB |
181ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen            NOTE_RENAME | NOTE_REVOKE | NOTE_EXTEND), 0, data);
182ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    events->push_back(event);
183ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
184ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  return last_existing_entry;
185ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
186ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
187ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenint FilePathWatcherImpl::FileDescriptorForPath(const FilePath& path) {
188ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  return HANDLE_EINTR(open(path.value().c_str(), O_EVTONLY));
189ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
190ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
191ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid FilePathWatcherImpl::CloseFileDescriptor(int *fd) {
192ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (*fd == -1) {
193ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    return;
194ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
195ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
196ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (HANDLE_EINTR(close(*fd)) != 0) {
197ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    PLOG(ERROR) << "close";
198ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
199ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  *fd = -1;
200ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
201ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
202ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenbool FilePathWatcherImpl::AreKeventValuesValid(struct kevent* kevents,
203ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                               int count) {
204ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (count < 0) {
205ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    PLOG(ERROR) << "kevent";
206ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    return false;
207ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
208ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  bool valid = true;
209ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  for (int i = 0; i < count; ++i) {
210ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    if (kevents[i].flags & EV_ERROR && kevents[i].data) {
211ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      // Find the kevent in |events_| that matches the kevent with the error.
212ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      EventVector::iterator event = events_.begin();
213ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      for (; event != events_.end(); ++event) {
214ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        if (event->ident == kevents[i].ident) {
215ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          break;
216ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        }
217ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      }
218ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      std::string path_name;
219ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      if (event != events_.end()) {
220ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        EventData* event_data = EventDataForKevent(*event);
221ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        if (event_data != NULL) {
222ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          path_name = event_data->path_.value();
223ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        }
224ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      }
225ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      if (path_name.empty()) {
226ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        path_name = base::StringPrintf(
227ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen            "fd %d", *reinterpret_cast<int*>(&kevents[i].ident));
228ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      }
229ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      LOG(ERROR) << "Error: " << kevents[i].data << " for " << path_name;
230ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      valid = false;
231ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    }
232ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
233ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  return valid;
234ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
235ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
236ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid FilePathWatcherImpl::HandleAttributesChange(
237ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    const EventVector::iterator& event,
238ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    bool* target_file_affected,
239ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    bool* update_watches) {
240ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  EventVector::iterator next_event = event + 1;
241ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  EventData* next_event_data = EventDataForKevent(*next_event);
242ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Check to see if the next item in path is still accessible.
243ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  int have_access = FileDescriptorForPath(next_event_data->path_);
244ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (have_access == -1) {
245ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    *target_file_affected = true;
246ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    *update_watches = true;
247ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    EventVector::iterator local_event(event);
248ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    for (; local_event != events_.end(); ++local_event) {
249ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      // Close all nodes from the event down. This has the side effect of
250ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      // potentially rendering other events in |updates| invalid.
251ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      // There is no need to remove the events from |kqueue_| because this
252ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      // happens as a side effect of closing the file descriptor.
253ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      CloseFileDescriptor(reinterpret_cast<int*>(&local_event->ident));
254ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    }
255ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  } else {
256ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    CloseFileDescriptor(&have_access);
257ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
258ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
259ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
260ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid FilePathWatcherImpl::HandleDeleteOrMoveChange(
261ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    const EventVector::iterator& event,
262ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    bool* target_file_affected,
263ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    bool* update_watches) {
264ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  *target_file_affected = true;
265ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  *update_watches = true;
266ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  EventVector::iterator local_event(event);
267ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  for (; local_event != events_.end(); ++local_event) {
268ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    // Close all nodes from the event down. This has the side effect of
269ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    // potentially rendering other events in |updates| invalid.
270ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    // There is no need to remove the events from |kqueue_| because this
271ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    // happens as a side effect of closing the file descriptor.
272ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    CloseFileDescriptor(reinterpret_cast<int*>(&local_event->ident));
273ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
274ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
275ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
276ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid FilePathWatcherImpl::HandleCreateItemChange(
277ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    const EventVector::iterator& event,
278ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    bool* target_file_affected,
279ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    bool* update_watches) {
280ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Get the next item in the path.
281ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  EventVector::iterator next_event = event + 1;
282ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  EventData* next_event_data = EventDataForKevent(*next_event);
283ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
284ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Check to see if it already has a valid file descriptor.
285ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (!IsKeventFileDescriptorOpen(*next_event)) {
286ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    // If not, attempt to open a file descriptor for it.
287ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    next_event->ident = FileDescriptorForPath(next_event_data->path_);
288ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    if (IsKeventFileDescriptorOpen(*next_event)) {
289ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      *update_watches = true;
290ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      if (next_event_data->subdir_.empty()) {
291ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        *target_file_affected = true;
292ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      }
293ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    }
294ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
295ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
296ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
297ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenbool FilePathWatcherImpl::UpdateWatches(bool* target_file_affected) {
298ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Iterate over events adding kevents for items that exist to the kqueue.
299ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Then check to see if new components in the path have been created.
300ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Repeat until no new components in the path are detected.
301ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // This is to get around races in directory creation in a watched path.
302ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  bool update_watches = true;
303ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  while (update_watches) {
304ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    size_t valid;
305ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    for (valid = 0; valid < events_.size(); ++valid) {
306ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      if (!IsKeventFileDescriptorOpen(events_[valid])) {
307ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        break;
308ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      }
309ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    }
310ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    if (valid == 0) {
311ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      // The root of the file path is inaccessible?
312ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      return false;
313ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    }
314ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
315ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    EventVector updates(valid);
316ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    int count = HANDLE_EINTR(kevent(kqueue_, &events_[0], valid, &updates[0],
317ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                    valid, NULL));
318ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    if (!AreKeventValuesValid(&updates[0], count)) {
319ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      return false;
320ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    }
321ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    update_watches = false;
322ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    for (; valid < events_.size(); ++valid) {
323ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      EventData* event_data = EventDataForKevent(events_[valid]);
324ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      events_[valid].ident = FileDescriptorForPath(event_data->path_);
325ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      if (IsKeventFileDescriptorOpen(events_[valid])) {
326ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        update_watches = true;
327ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        if (event_data->subdir_.empty()) {
328ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          *target_file_affected = true;
329ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        }
330ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      } else {
331ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        break;
332ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      }
333ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    }
334ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
335ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  return true;
336ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
337ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
338ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid FilePathWatcherImpl::OnFileCanReadWithoutBlocking(int fd) {
339ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  DCHECK(MessageLoopForIO::current());
340ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  CHECK_EQ(fd, kqueue_);
341ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  CHECK(events_.size());
342ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
343ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Request the file system update notifications that have occurred and return
344ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // them in |updates|. |count| will contain the number of updates that have
345ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // occurred.
346ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  EventVector updates(events_.size());
347ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  struct timespec timeout = {0, 0};
348ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  int count = HANDLE_EINTR(kevent(kqueue_, NULL, 0, &updates[0], updates.size(),
349ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                  &timeout));
350ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
351ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Error values are stored within updates, so check to make sure that no
352ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // errors occurred.
353ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (!AreKeventValuesValid(&updates[0], count)) {
354ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    delegate_->OnFilePathError(target_);
355ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    Cancel();
356ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    return;
357ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
358ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
359ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  bool update_watches = false;
360ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  bool send_notification = false;
361ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
362ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Iterate through each of the updates and react to them.
363ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  for (int i = 0; i < count; ++i) {
364ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    // Find our kevent record that matches the update notification.
365ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    EventVector::iterator event = events_.begin();
366ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    for (; event != events_.end(); ++event) {
367ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      if (!IsKeventFileDescriptorOpen(*event) ||
368ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          event->ident == updates[i].ident) {
369ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        break;
370ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      }
371ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    }
372ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    if (!IsKeventFileDescriptorOpen(*event) || event == events_.end()) {
373ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      // The event may no longer exist in |events_| because another event
374ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      // modified |events_| in such a way to make it invalid. For example if
375ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      // the path is /foo/bar/bam and foo is deleted, NOTE_DELETE events for
376ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      // foo, bar and bam will be sent. If foo is processed first, then
377ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      // the file descriptors for bar and bam will already be closed and set
378ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      // to -1 before they get a chance to be processed.
379ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      continue;
380ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    }
381ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
382ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    EventData* event_data = EventDataForKevent(*event);
383ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
384ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    // If the subdir is empty, this is the last item on the path and is the
385ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    // target file.
386ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    bool target_file_affected = event_data->subdir_.empty();
387ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    if ((updates[i].fflags & NOTE_ATTRIB) && !target_file_affected) {
388ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      HandleAttributesChange(event, &target_file_affected, &update_watches);
389ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    }
390ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    if (updates[i].fflags & (NOTE_DELETE | NOTE_REVOKE | NOTE_RENAME)) {
391ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      HandleDeleteOrMoveChange(event, &target_file_affected, &update_watches);
392ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    }
393ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    if ((updates[i].fflags & NOTE_WRITE) && !target_file_affected) {
394ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      HandleCreateItemChange(event, &target_file_affected, &update_watches);
395ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    }
396ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    send_notification |= target_file_affected;
397ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
398ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
399ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (update_watches) {
400ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    if (!UpdateWatches(&send_notification)) {
401ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      delegate_->OnFilePathError(target_);
402ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      Cancel();
403ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    }
404ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
405ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
406ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (send_notification) {
407ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    delegate_->OnFilePathChanged(target_);
408ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
409ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
410ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
411ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid FilePathWatcherImpl::OnFileCanWriteWithoutBlocking(int fd) {
412ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  NOTREACHED();
413ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
414ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
415ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid FilePathWatcherImpl::WillDestroyCurrentMessageLoop() {
416ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  CancelOnMessageLoopThread();
417ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
418ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
419ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenbool FilePathWatcherImpl::Watch(const FilePath& path,
420ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                FilePathWatcher::Delegate* delegate) {
421ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  DCHECK(MessageLoopForIO::current());
422ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  DCHECK(target_.value().empty());  // Can only watch one path.
423ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  DCHECK(delegate);
424ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  DCHECK_EQ(kqueue_, -1);
425ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
426ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  delegate_ = delegate;
427ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  target_ = path;
428ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
429ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  MessageLoop::current()->AddDestructionObserver(this);
430ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  io_message_loop_ = base::MessageLoopProxy::CreateForCurrentThread();
431ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
432ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  kqueue_ = kqueue();
433ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (kqueue_ == -1) {
434ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    PLOG(ERROR) << "kqueue";
435ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    return false;
436ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
437ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
438ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  int last_entry = EventsForPath(target_, &events_);
439ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  CHECK_NE(last_entry, 0);
440ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
441ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  EventVector responses(last_entry);
442ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
443ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  int count = HANDLE_EINTR(kevent(kqueue_, &events_[0], last_entry,
444ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                  &responses[0], last_entry, NULL));
445ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (!AreKeventValuesValid(&responses[0], count)) {
446ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    // Calling Cancel() here to close any file descriptors that were opened.
447ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    // This would happen in the destructor anyways, but FilePathWatchers tend to
448ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    // be long lived, and if an error has occurred, there is no reason to waste
449ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    // the file descriptors.
450ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    Cancel();
451ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    return false;
452ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
453ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
454ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  return MessageLoopForIO::current()->WatchFileDescriptor(
455ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      kqueue_, true, MessageLoopForIO::WATCH_READ, &kqueue_watcher_, this);
456ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
457ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
458ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid FilePathWatcherImpl::Cancel() {
459ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  base::MessageLoopProxy* proxy = io_message_loop_.get();
460ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (!proxy) {
461ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    set_cancelled();
462ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    return;
463ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
464ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (!proxy->BelongsToCurrentThread()) {
465ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    proxy->PostTask(FROM_HERE,
466ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                    NewRunnableMethod(this, &FilePathWatcherImpl::Cancel));
467ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    return;
468ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
469ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  CancelOnMessageLoopThread();
470ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
471ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
472ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid FilePathWatcherImpl::CancelOnMessageLoopThread() {
473ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  DCHECK(MessageLoopForIO::current());
474ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (!is_cancelled()) {
475ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    set_cancelled();
476ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    kqueue_watcher_.StopWatchingFileDescriptor();
477ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    CloseFileDescriptor(&kqueue_);
478ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    std::for_each(events_.begin(), events_.end(), ReleaseEvent);
479ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    events_.clear();
480ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    io_message_loop_ = NULL;
481ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    MessageLoop::current()->RemoveDestructionObserver(this);
482ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    delegate_ = NULL;
483ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
484ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
485ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
486ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}  // namespace
487ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
488ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian MonsenFilePathWatcher::FilePathWatcher() {
489ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  impl_ = new FilePathWatcherImpl();
490ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
491ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
492ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}  // namespace files
493ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}  // namespace base
494