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