15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "base/files/file_path_watcher_kqueue.h" 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <fcntl.h> 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <sys/param.h> 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h" 116e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include "base/files/file_util.h" 122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/logging.h" 135e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles)#include "base/strings/stringprintf.h" 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// On some platforms these are not defined. 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if !defined(EV_RECEIPT) 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define EV_RECEIPT 0 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if !defined(O_EVTONLY) 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define O_EVTONLY O_RDONLY 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace base { 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 25f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)FilePathWatcherKQueue::FilePathWatcherKQueue() : kqueue_(-1) {} 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 27f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)FilePathWatcherKQueue::~FilePathWatcherKQueue() {} 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 29f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void FilePathWatcherKQueue::ReleaseEvent(struct kevent& event) { 30c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) CloseFileDescriptor(&event.ident); 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EventData* entry = EventDataForKevent(event); 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) delete entry; 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) event.udata = NULL; 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 36f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)int FilePathWatcherKQueue::EventsForPath(FilePath path, EventVector* events) { 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(MessageLoopForIO::current()); 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Make sure that we are working with a clean slate. 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(events->empty()); 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::vector<FilePath::StringType> components; 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) path.GetComponents(&components); 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (components.size() < 1) { 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return -1; 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int last_existing_entry = 0; 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FilePath built_path; 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool path_still_exists = true; 51a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) for (std::vector<FilePath::StringType>::iterator i = components.begin(); 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) i != components.end(); ++i) { 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (i == components.begin()) { 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) built_path = FilePath(*i); 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) built_path = built_path.Append(*i); 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 58c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) uintptr_t fd = kNoFileDescriptor; 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (path_still_exists) { 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fd = FileDescriptorForPath(built_path); 61c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (fd == kNoFileDescriptor) { 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) path_still_exists = false; 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ++last_existing_entry; 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FilePath::StringType subdir = (i != (components.end() - 1)) ? *(i + 1) : ""; 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EventData* data = new EventData(built_path, subdir); 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct kevent event; 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EV_SET(&event, fd, EVFILT_VNODE, (EV_ADD | EV_CLEAR | EV_RECEIPT), 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (NOTE_DELETE | NOTE_WRITE | NOTE_ATTRIB | 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTE_RENAME | NOTE_REVOKE | NOTE_EXTEND), 0, data); 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) events->push_back(event); 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return last_existing_entry; 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 78f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)uintptr_t FilePathWatcherKQueue::FileDescriptorForPath(const FilePath& path) { 79c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) int fd = HANDLE_EINTR(open(path.value().c_str(), O_EVTONLY)); 80c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (fd == -1) 81c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return kNoFileDescriptor; 82c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return fd; 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 85f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void FilePathWatcherKQueue::CloseFileDescriptor(uintptr_t* fd) { 86c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (*fd == kNoFileDescriptor) { 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 90a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (IGNORE_EINTR(close(*fd)) != 0) { 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DPLOG(ERROR) << "close"; 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 93c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) *fd = kNoFileDescriptor; 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 96f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)bool FilePathWatcherKQueue::AreKeventValuesValid(struct kevent* kevents, 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int count) { 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (count < 0) { 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DPLOG(ERROR) << "kevent"; 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool valid = true; 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int i = 0; i < count; ++i) { 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (kevents[i].flags & EV_ERROR && kevents[i].data) { 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Find the kevent in |events_| that matches the kevent with the error. 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EventVector::iterator event = events_.begin(); 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (; event != events_.end(); ++event) { 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (event->ident == kevents[i].ident) { 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string path_name; 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (event != events_.end()) { 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EventData* event_data = EventDataForKevent(*event); 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (event_data != NULL) { 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) path_name = event_data->path_.value(); 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (path_name.empty()) { 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) path_name = base::StringPrintf( 121c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) "fd %ld", reinterpret_cast<long>(&kevents[i].ident)); 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DLOG(ERROR) << "Error: " << kevents[i].data << " for " << path_name; 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) valid = false; 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return valid; 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 130f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void FilePathWatcherKQueue::HandleAttributesChange( 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const EventVector::iterator& event, 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool* target_file_affected, 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool* update_watches) { 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EventVector::iterator next_event = event + 1; 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EventData* next_event_data = EventDataForKevent(*next_event); 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Check to see if the next item in path is still accessible. 137c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) uintptr_t have_access = FileDescriptorForPath(next_event_data->path_); 138c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (have_access == kNoFileDescriptor) { 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *target_file_affected = true; 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *update_watches = true; 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EventVector::iterator local_event(event); 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (; local_event != events_.end(); ++local_event) { 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Close all nodes from the event down. This has the side effect of 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // potentially rendering other events in |updates| invalid. 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // There is no need to remove the events from |kqueue_| because this 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // happens as a side effect of closing the file descriptor. 147c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) CloseFileDescriptor(&local_event->ident); 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CloseFileDescriptor(&have_access); 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 154f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void FilePathWatcherKQueue::HandleDeleteOrMoveChange( 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const EventVector::iterator& event, 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool* target_file_affected, 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool* update_watches) { 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *target_file_affected = true; 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *update_watches = true; 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EventVector::iterator local_event(event); 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (; local_event != events_.end(); ++local_event) { 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Close all nodes from the event down. This has the side effect of 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // potentially rendering other events in |updates| invalid. 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // There is no need to remove the events from |kqueue_| because this 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // happens as a side effect of closing the file descriptor. 166c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) CloseFileDescriptor(&local_event->ident); 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 170f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void FilePathWatcherKQueue::HandleCreateItemChange( 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const EventVector::iterator& event, 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool* target_file_affected, 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool* update_watches) { 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Get the next item in the path. 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EventVector::iterator next_event = event + 1; 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Check to see if it already has a valid file descriptor. 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!IsKeventFileDescriptorOpen(*next_event)) { 178c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) EventData* next_event_data = EventDataForKevent(*next_event); 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If not, attempt to open a file descriptor for it. 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) next_event->ident = FileDescriptorForPath(next_event_data->path_); 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (IsKeventFileDescriptorOpen(*next_event)) { 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *update_watches = true; 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (next_event_data->subdir_.empty()) { 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *target_file_affected = true; 1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 190f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)bool FilePathWatcherKQueue::UpdateWatches(bool* target_file_affected) { 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Iterate over events adding kevents for items that exist to the kqueue. 1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Then check to see if new components in the path have been created. 1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Repeat until no new components in the path are detected. 1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This is to get around races in directory creation in a watched path. 1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool update_watches = true; 1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (update_watches) { 1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t valid; 1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (valid = 0; valid < events_.size(); ++valid) { 1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!IsKeventFileDescriptorOpen(events_[valid])) { 2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (valid == 0) { 2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The root of the file path is inaccessible? 2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EventVector updates(valid); 2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int count = HANDLE_EINTR(kevent(kqueue_, &events_[0], valid, &updates[0], 2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) valid, NULL)); 2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!AreKeventValuesValid(&updates[0], count)) { 2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) update_watches = false; 2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (; valid < events_.size(); ++valid) { 2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EventData* event_data = EventDataForKevent(events_[valid]); 2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) events_[valid].ident = FileDescriptorForPath(event_data->path_); 2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (IsKeventFileDescriptorOpen(events_[valid])) { 2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) update_watches = true; 2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (event_data->subdir_.empty()) { 2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *target_file_affected = true; 2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 231f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void FilePathWatcherKQueue::OnFileCanReadWithoutBlocking(int fd) { 2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(MessageLoopForIO::current()); 2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_EQ(fd, kqueue_); 2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(events_.size()); 2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Request the file system update notifications that have occurred and return 2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // them in |updates|. |count| will contain the number of updates that have 2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // occurred. 2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EventVector updates(events_.size()); 2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct timespec timeout = {0, 0}; 2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int count = HANDLE_EINTR(kevent(kqueue_, NULL, 0, &updates[0], updates.size(), 2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &timeout)); 2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Error values are stored within updates, so check to make sure that no 2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // errors occurred. 2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!AreKeventValuesValid(&updates[0], count)) { 2472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) callback_.Run(target_, true /* error */); 2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Cancel(); 2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool update_watches = false; 2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool send_notification = false; 2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Iterate through each of the updates and react to them. 2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int i = 0; i < count; ++i) { 2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Find our kevent record that matches the update notification. 2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EventVector::iterator event = events_.begin(); 2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (; event != events_.end(); ++event) { 2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!IsKeventFileDescriptorOpen(*event) || 2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) event->ident == updates[i].ident) { 2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 265c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (event == events_.end() || !IsKeventFileDescriptorOpen(*event)) { 2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The event may no longer exist in |events_| because another event 2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // modified |events_| in such a way to make it invalid. For example if 2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // the path is /foo/bar/bam and foo is deleted, NOTE_DELETE events for 2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // foo, bar and bam will be sent. If foo is processed first, then 2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // the file descriptors for bar and bam will already be closed and set 2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // to -1 before they get a chance to be processed. 2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) continue; 2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EventData* event_data = EventDataForKevent(*event); 2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If the subdir is empty, this is the last item on the path and is the 2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // target file. 2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool target_file_affected = event_data->subdir_.empty(); 2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ((updates[i].fflags & NOTE_ATTRIB) && !target_file_affected) { 2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HandleAttributesChange(event, &target_file_affected, &update_watches); 2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (updates[i].fflags & (NOTE_DELETE | NOTE_REVOKE | NOTE_RENAME)) { 2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HandleDeleteOrMoveChange(event, &target_file_affected, &update_watches); 2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ((updates[i].fflags & NOTE_WRITE) && !target_file_affected) { 2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HandleCreateItemChange(event, &target_file_affected, &update_watches); 2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) send_notification |= target_file_affected; 2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (update_watches) { 2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!UpdateWatches(&send_notification)) { 2942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) callback_.Run(target_, true /* error */); 2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Cancel(); 2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (send_notification) { 3002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) callback_.Run(target_, false); 3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 304f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void FilePathWatcherKQueue::OnFileCanWriteWithoutBlocking(int fd) { 3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED(); 3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 308f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void FilePathWatcherKQueue::WillDestroyCurrentMessageLoop() { 3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CancelOnMessageLoopThread(); 3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 312f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)bool FilePathWatcherKQueue::Watch(const FilePath& path, 313f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) bool recursive, 314f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) const FilePathWatcher::Callback& callback) { 3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(MessageLoopForIO::current()); 3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(target_.value().empty()); // Can only watch one path. 3172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(!callback.is_null()); 3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_EQ(kqueue_, -1); 3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (recursive) { 321f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // Recursive watch is not supported using kqueue. 3222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) NOTIMPLEMENTED(); 3232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return false; 3242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 3252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) callback_ = callback; 3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) target_ = path; 3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MessageLoop::current()->AddDestructionObserver(this); 3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) io_message_loop_ = base::MessageLoopProxy::current(); 3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kqueue_ = kqueue(); 3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (kqueue_ == -1) { 3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DPLOG(ERROR) << "kqueue"; 3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int last_entry = EventsForPath(target_, &events_); 3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_NE(last_entry, 0); 3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EventVector responses(last_entry); 3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int count = HANDLE_EINTR(kevent(kqueue_, &events_[0], last_entry, 3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &responses[0], last_entry, NULL)); 3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!AreKeventValuesValid(&responses[0], count)) { 3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Calling Cancel() here to close any file descriptors that were opened. 3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This would happen in the destructor anyways, but FilePathWatchers tend to 3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // be long lived, and if an error has occurred, there is no reason to waste 3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // the file descriptors. 3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Cancel(); 3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return MessageLoopForIO::current()->WatchFileDescriptor( 3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kqueue_, true, MessageLoopForIO::WATCH_READ, &kqueue_watcher_, this); 3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 358f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void FilePathWatcherKQueue::Cancel() { 3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::MessageLoopProxy* proxy = io_message_loop_.get(); 3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!proxy) { 3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) set_cancelled(); 3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!proxy->BelongsToCurrentThread()) { 3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) proxy->PostTask(FROM_HERE, 366f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) base::Bind(&FilePathWatcherKQueue::Cancel, this)); 3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CancelOnMessageLoopThread(); 3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 372f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void FilePathWatcherKQueue::CancelOnMessageLoopThread() { 3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(MessageLoopForIO::current()); 3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!is_cancelled()) { 3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) set_cancelled(); 3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kqueue_watcher_.StopWatchingFileDescriptor(); 377a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (IGNORE_EINTR(close(kqueue_)) != 0) { 378c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) DPLOG(ERROR) << "close kqueue"; 379c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 380c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) kqueue_ = -1; 3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::for_each(events_.begin(), events_.end(), ReleaseEvent); 3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) events_.clear(); 3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) io_message_loop_ = NULL; 3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MessageLoop::current()->RemoveDestructionObserver(this); 3852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) callback_.Reset(); 3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace base 390