1b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// Use of this source code is governed by a BSD-style license that can be
3b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// found in the LICENSE file.
4b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
5b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat#include "base/files/file_path_watcher_kqueue.h"
6b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
7b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat#include <fcntl.h>
8cce46a0c214b37e8da48c522c83037e8ffa4f9fdAlex Vakulenko#include <stddef.h>
9b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat#include <sys/param.h>
10b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
11b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat#include "base/bind.h"
12b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat#include "base/files/file_util.h"
13b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat#include "base/logging.h"
14b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat#include "base/strings/stringprintf.h"
15b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat#include "base/thread_task_runner_handle.h"
16b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
17b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// On some platforms these are not defined.
18b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat#if !defined(EV_RECEIPT)
19b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat#define EV_RECEIPT 0
20b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat#endif
21b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat#if !defined(O_EVTONLY)
22b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat#define O_EVTONLY O_RDONLY
23b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat#endif
24b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
25b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratnamespace base {
26b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
27b8cf94937c52feb53b55c39e3f82094d27de464cDaniel EratFilePathWatcherKQueue::FilePathWatcherKQueue() : kqueue_(-1) {}
28b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
29b8cf94937c52feb53b55c39e3f82094d27de464cDaniel EratFilePathWatcherKQueue::~FilePathWatcherKQueue() {}
30b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
31b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratvoid FilePathWatcherKQueue::ReleaseEvent(struct kevent& event) {
32b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  CloseFileDescriptor(&event.ident);
33b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  EventData* entry = EventDataForKevent(event);
34b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  delete entry;
35b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  event.udata = NULL;
36b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat}
37b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
38b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratint FilePathWatcherKQueue::EventsForPath(FilePath path, EventVector* events) {
39b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  DCHECK(MessageLoopForIO::current());
40b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // Make sure that we are working with a clean slate.
41b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  DCHECK(events->empty());
42b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
43b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  std::vector<FilePath::StringType> components;
44b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  path.GetComponents(&components);
45b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
46b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  if (components.size() < 1) {
47b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    return -1;
48b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  }
49b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
50b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  int last_existing_entry = 0;
51b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  FilePath built_path;
52b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  bool path_still_exists = true;
53b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  for (std::vector<FilePath::StringType>::iterator i = components.begin();
54b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat      i != components.end(); ++i) {
55b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    if (i == components.begin()) {
56b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat      built_path = FilePath(*i);
57b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    } else {
58b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat      built_path = built_path.Append(*i);
59b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    }
60b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    uintptr_t fd = kNoFileDescriptor;
61b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    if (path_still_exists) {
62b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat      fd = FileDescriptorForPath(built_path);
63b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat      if (fd == kNoFileDescriptor) {
64b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat        path_still_exists = false;
65b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat      } else {
66b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat        ++last_existing_entry;
67b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat      }
68b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    }
69b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    FilePath::StringType subdir = (i != (components.end() - 1)) ? *(i + 1) : "";
70b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    EventData* data = new EventData(built_path, subdir);
71b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    struct kevent event;
72b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    EV_SET(&event, fd, EVFILT_VNODE, (EV_ADD | EV_CLEAR | EV_RECEIPT),
73b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat           (NOTE_DELETE | NOTE_WRITE | NOTE_ATTRIB |
74b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat            NOTE_RENAME | NOTE_REVOKE | NOTE_EXTEND), 0, data);
75b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    events->push_back(event);
76b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  }
77b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  return last_existing_entry;
78b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat}
79b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
80b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratuintptr_t FilePathWatcherKQueue::FileDescriptorForPath(const FilePath& path) {
81b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  int fd = HANDLE_EINTR(open(path.value().c_str(), O_EVTONLY));
82b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  if (fd == -1)
83b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    return kNoFileDescriptor;
84b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  return fd;
85b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat}
86b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
87b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratvoid FilePathWatcherKQueue::CloseFileDescriptor(uintptr_t* fd) {
88b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  if (*fd == kNoFileDescriptor) {
89b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    return;
90b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  }
91b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
92b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  if (IGNORE_EINTR(close(*fd)) != 0) {
93b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    DPLOG(ERROR) << "close";
94b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  }
95b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  *fd = kNoFileDescriptor;
96b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat}
97b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
98b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratbool FilePathWatcherKQueue::AreKeventValuesValid(struct kevent* kevents,
99b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat                                               int count) {
100b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  if (count < 0) {
101b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    DPLOG(ERROR) << "kevent";
102b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    return false;
103b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  }
104b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  bool valid = true;
105b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  for (int i = 0; i < count; ++i) {
106b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    if (kevents[i].flags & EV_ERROR && kevents[i].data) {
107b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat      // Find the kevent in |events_| that matches the kevent with the error.
108b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat      EventVector::iterator event = events_.begin();
109b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat      for (; event != events_.end(); ++event) {
110b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat        if (event->ident == kevents[i].ident) {
111b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat          break;
112b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat        }
113b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat      }
114b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat      std::string path_name;
115b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat      if (event != events_.end()) {
116b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat        EventData* event_data = EventDataForKevent(*event);
117b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat        if (event_data != NULL) {
118b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat          path_name = event_data->path_.value();
119b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat        }
120b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat      }
121b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat      if (path_name.empty()) {
122b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat        path_name = base::StringPrintf(
123b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat            "fd %ld", reinterpret_cast<long>(&kevents[i].ident));
124b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat      }
125b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat      DLOG(ERROR) << "Error: " << kevents[i].data << " for " << path_name;
126b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat      valid = false;
127b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    }
128b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  }
129b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  return valid;
130b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat}
131b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
132b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratvoid FilePathWatcherKQueue::HandleAttributesChange(
133b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    const EventVector::iterator& event,
134b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    bool* target_file_affected,
135b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    bool* update_watches) {
136b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  EventVector::iterator next_event = event + 1;
137b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  EventData* next_event_data = EventDataForKevent(*next_event);
138b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // Check to see if the next item in path is still accessible.
139b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  uintptr_t have_access = FileDescriptorForPath(next_event_data->path_);
140b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  if (have_access == kNoFileDescriptor) {
141b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    *target_file_affected = true;
142b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    *update_watches = true;
143b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    EventVector::iterator local_event(event);
144b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    for (; local_event != events_.end(); ++local_event) {
145b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat      // Close all nodes from the event down. This has the side effect of
146b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat      // potentially rendering other events in |updates| invalid.
147b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat      // There is no need to remove the events from |kqueue_| because this
148b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat      // happens as a side effect of closing the file descriptor.
149b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat      CloseFileDescriptor(&local_event->ident);
150b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    }
151b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  } else {
152b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    CloseFileDescriptor(&have_access);
153b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  }
154b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat}
155b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
156b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratvoid FilePathWatcherKQueue::HandleDeleteOrMoveChange(
157b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    const EventVector::iterator& event,
158b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    bool* target_file_affected,
159b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    bool* update_watches) {
160b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  *target_file_affected = true;
161b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  *update_watches = true;
162b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  EventVector::iterator local_event(event);
163b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  for (; local_event != events_.end(); ++local_event) {
164b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    // Close all nodes from the event down. This has the side effect of
165b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    // potentially rendering other events in |updates| invalid.
166b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    // There is no need to remove the events from |kqueue_| because this
167b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    // happens as a side effect of closing the file descriptor.
168b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    CloseFileDescriptor(&local_event->ident);
169b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  }
170b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat}
171b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
172b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratvoid FilePathWatcherKQueue::HandleCreateItemChange(
173b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    const EventVector::iterator& event,
174b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    bool* target_file_affected,
175b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    bool* update_watches) {
176b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // Get the next item in the path.
177b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  EventVector::iterator next_event = event + 1;
178b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // Check to see if it already has a valid file descriptor.
179b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  if (!IsKeventFileDescriptorOpen(*next_event)) {
180b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    EventData* next_event_data = EventDataForKevent(*next_event);
181b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    // If not, attempt to open a file descriptor for it.
182b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    next_event->ident = FileDescriptorForPath(next_event_data->path_);
183b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    if (IsKeventFileDescriptorOpen(*next_event)) {
184b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat      *update_watches = true;
185b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat      if (next_event_data->subdir_.empty()) {
186b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat        *target_file_affected = true;
187b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat      }
188b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    }
189b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  }
190b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat}
191b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
192b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratbool FilePathWatcherKQueue::UpdateWatches(bool* target_file_affected) {
193b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // Iterate over events adding kevents for items that exist to the kqueue.
194b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // Then check to see if new components in the path have been created.
195b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // Repeat until no new components in the path are detected.
196b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // This is to get around races in directory creation in a watched path.
197b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  bool update_watches = true;
198b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  while (update_watches) {
199b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    size_t valid;
200b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    for (valid = 0; valid < events_.size(); ++valid) {
201b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat      if (!IsKeventFileDescriptorOpen(events_[valid])) {
202b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat        break;
203b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat      }
204b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    }
205b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    if (valid == 0) {
206b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat      // The root of the file path is inaccessible?
207b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat      return false;
208b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    }
209b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
210b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    EventVector updates(valid);
211b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    int count = HANDLE_EINTR(kevent(kqueue_, &events_[0], valid, &updates[0],
212b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat                                    valid, NULL));
213b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    if (!AreKeventValuesValid(&updates[0], count)) {
214b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat      return false;
215b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    }
216b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    update_watches = false;
217b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    for (; valid < events_.size(); ++valid) {
218b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat      EventData* event_data = EventDataForKevent(events_[valid]);
219b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat      events_[valid].ident = FileDescriptorForPath(event_data->path_);
220b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat      if (IsKeventFileDescriptorOpen(events_[valid])) {
221b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat        update_watches = true;
222b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat        if (event_data->subdir_.empty()) {
223b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat          *target_file_affected = true;
224b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat        }
225b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat      } else {
226b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat        break;
227b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat      }
228b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    }
229b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  }
230b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  return true;
231b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat}
232b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
233b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratvoid FilePathWatcherKQueue::OnFileCanReadWithoutBlocking(int fd) {
234b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  DCHECK(MessageLoopForIO::current());
235b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  DCHECK_EQ(fd, kqueue_);
236b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  DCHECK(events_.size());
237b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
238b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // Request the file system update notifications that have occurred and return
239b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // them in |updates|. |count| will contain the number of updates that have
240b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // occurred.
241b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  EventVector updates(events_.size());
242b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  struct timespec timeout = {0, 0};
243b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  int count = HANDLE_EINTR(kevent(kqueue_, NULL, 0, &updates[0], updates.size(),
244b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat                                  &timeout));
245b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
246b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // Error values are stored within updates, so check to make sure that no
247b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // errors occurred.
248b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  if (!AreKeventValuesValid(&updates[0], count)) {
249b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    callback_.Run(target_, true /* error */);
250b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    Cancel();
251b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    return;
252b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  }
253b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
254b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  bool update_watches = false;
255b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  bool send_notification = false;
256b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
257b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // Iterate through each of the updates and react to them.
258b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  for (int i = 0; i < count; ++i) {
259b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    // Find our kevent record that matches the update notification.
260b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    EventVector::iterator event = events_.begin();
261b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    for (; event != events_.end(); ++event) {
262b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat      if (!IsKeventFileDescriptorOpen(*event) ||
263b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat          event->ident == updates[i].ident) {
264b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat        break;
265b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat      }
266b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    }
267b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    if (event == events_.end() || !IsKeventFileDescriptorOpen(*event)) {
268b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat      // The event may no longer exist in |events_| because another event
269b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat      // modified |events_| in such a way to make it invalid. For example if
270b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat      // the path is /foo/bar/bam and foo is deleted, NOTE_DELETE events for
271b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat      // foo, bar and bam will be sent. If foo is processed first, then
272b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat      // the file descriptors for bar and bam will already be closed and set
273b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat      // to -1 before they get a chance to be processed.
274b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat      continue;
275b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    }
276b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
277b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    EventData* event_data = EventDataForKevent(*event);
278b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
279b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    // If the subdir is empty, this is the last item on the path and is the
280b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    // target file.
281b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    bool target_file_affected = event_data->subdir_.empty();
282b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    if ((updates[i].fflags & NOTE_ATTRIB) && !target_file_affected) {
283b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat      HandleAttributesChange(event, &target_file_affected, &update_watches);
284b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    }
285b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    if (updates[i].fflags & (NOTE_DELETE | NOTE_REVOKE | NOTE_RENAME)) {
286b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat      HandleDeleteOrMoveChange(event, &target_file_affected, &update_watches);
287b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    }
288b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    if ((updates[i].fflags & NOTE_WRITE) && !target_file_affected) {
289b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat      HandleCreateItemChange(event, &target_file_affected, &update_watches);
290b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    }
291b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    send_notification |= target_file_affected;
292b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  }
293b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
294b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  if (update_watches) {
295b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    if (!UpdateWatches(&send_notification)) {
296b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat      callback_.Run(target_, true /* error */);
297b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat      Cancel();
298b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    }
299b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  }
300b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
301b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  if (send_notification) {
302b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    callback_.Run(target_, false);
303b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  }
304b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat}
305b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
3063bf7081cf806cd9ebedb47b3eff76671794efa68Christopher Wileyvoid FilePathWatcherKQueue::OnFileCanWriteWithoutBlocking(int /* fd */) {
307b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  NOTREACHED();
308b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat}
309b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
310b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratvoid FilePathWatcherKQueue::WillDestroyCurrentMessageLoop() {
311b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  CancelOnMessageLoopThread();
312b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat}
313b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
314b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratbool FilePathWatcherKQueue::Watch(const FilePath& path,
315b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat                                  bool recursive,
316b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat                                  const FilePathWatcher::Callback& callback) {
317b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  DCHECK(MessageLoopForIO::current());
318b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  DCHECK(target_.value().empty());  // Can only watch one path.
319b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  DCHECK(!callback.is_null());
320b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  DCHECK_EQ(kqueue_, -1);
321b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
322b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  if (recursive) {
323b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    // Recursive watch is not supported using kqueue.
324b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    NOTIMPLEMENTED();
325b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    return false;
326b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  }
327b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
328b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  callback_ = callback;
329b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  target_ = path;
330b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
331b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  MessageLoop::current()->AddDestructionObserver(this);
332b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  io_task_runner_ = ThreadTaskRunnerHandle::Get();
333b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
334b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  kqueue_ = kqueue();
335b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  if (kqueue_ == -1) {
336b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    DPLOG(ERROR) << "kqueue";
337b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    return false;
338b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  }
339b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
340b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  int last_entry = EventsForPath(target_, &events_);
341b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  DCHECK_NE(last_entry, 0);
342b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
343b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  EventVector responses(last_entry);
344b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
345b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  int count = HANDLE_EINTR(kevent(kqueue_, &events_[0], last_entry,
346b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat                                  &responses[0], last_entry, NULL));
347b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  if (!AreKeventValuesValid(&responses[0], count)) {
348b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    // Calling Cancel() here to close any file descriptors that were opened.
349b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    // This would happen in the destructor anyways, but FilePathWatchers tend to
350b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    // be long lived, and if an error has occurred, there is no reason to waste
351b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    // the file descriptors.
352b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    Cancel();
353b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    return false;
354b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  }
355b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
356b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  return MessageLoopForIO::current()->WatchFileDescriptor(
357b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat      kqueue_, true, MessageLoopForIO::WATCH_READ, &kqueue_watcher_, this);
358b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat}
359b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
360b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratvoid FilePathWatcherKQueue::Cancel() {
361b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  SingleThreadTaskRunner* task_runner = io_task_runner_.get();
362b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  if (!task_runner) {
363b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    set_cancelled();
364b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    return;
365b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  }
366b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  if (!task_runner->BelongsToCurrentThread()) {
367b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    task_runner->PostTask(FROM_HERE,
368b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat                          base::Bind(&FilePathWatcherKQueue::Cancel, this));
369b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    return;
370b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  }
371b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  CancelOnMessageLoopThread();
372b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat}
373b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
374b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratvoid FilePathWatcherKQueue::CancelOnMessageLoopThread() {
375b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  DCHECK(MessageLoopForIO::current());
376b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  if (!is_cancelled()) {
377b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    set_cancelled();
378b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    kqueue_watcher_.StopWatchingFileDescriptor();
379b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    if (IGNORE_EINTR(close(kqueue_)) != 0) {
380b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat      DPLOG(ERROR) << "close kqueue";
381b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    }
382b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    kqueue_ = -1;
383b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    std::for_each(events_.begin(), events_.end(), ReleaseEvent);
384b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    events_.clear();
385b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    io_task_runner_ = NULL;
386b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    MessageLoop::current()->RemoveDestructionObserver(this);
387b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    callback_.Reset();
388b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  }
389b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat}
390b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
391b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat}  // namespace base
392