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