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) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/files/file_path_watcher.h" 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <fcntl.h> 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <sys/event.h> 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <sys/param.h> 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <vector> 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h" 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/file_util.h" 152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/logging.h" 16ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch#include "base/message_loop/message_loop.h" 17868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/message_loop/message_loop_proxy.h" 185e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles)#include "base/strings/stringprintf.h" 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// On some platforms these are not defined. 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if !defined(EV_RECEIPT) 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define EV_RECEIPT 0 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if !defined(O_EVTONLY) 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define O_EVTONLY O_RDONLY 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace base { 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace { 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Mac-specific file watcher implementation based on kqueue. 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Originally it was based on FSEvents so that the semantics were equivalent 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// on Linux, OSX and Windows where it was able to detect: 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// - file creation/deletion/modification in a watched directory 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// - file creation/deletion/modification for a watched file 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// - modifications to the paths to a watched object that would affect the 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// object such as renaming/attibute changes etc. 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The FSEvents version did all of the above except handling attribute changes 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// to path components. Unfortunately FSEvents appears to have an issue where the 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// current implementation (Mac OS X 10.6.7) sometimes drops events and doesn't 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// send notifications. See 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// http://code.google.com/p/chromium/issues/detail?id=54822#c31 for source that 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// will reproduce the problem. FSEvents also required having a CFRunLoop 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// backing the thread that it was running on, that caused added complexity 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// in the interfaces. 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The kqueue implementation will handle all of the items in the list above 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// except for detecting modifications to files in a watched directory. It will 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// detect the creation and deletion of files, just not the modification of 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// files. It does however detect the attribute changes that the FSEvents impl 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// would miss. 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class FilePathWatcherImpl : public FilePathWatcher::PlatformDelegate, 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public MessageLoopForIO::Watcher, 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public MessageLoop::DestructionObserver { 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public: 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FilePathWatcherImpl() : kqueue_(-1) {} 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // MessageLoopForIO::Watcher overrides. 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual void OnFileCanReadWithoutBlocking(int fd) OVERRIDE; 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual void OnFileCanWriteWithoutBlocking(int fd) OVERRIDE; 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // MessageLoop::DestructionObserver overrides. 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual void WillDestroyCurrentMessageLoop() OVERRIDE; 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // FilePathWatcher::PlatformDelegate overrides. 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual bool Watch(const FilePath& path, 672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) bool recursive, 682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const FilePathWatcher::Callback& callback) OVERRIDE; 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual void Cancel() OVERRIDE; 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) protected: 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual ~FilePathWatcherImpl() {} 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private: 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) class EventData { 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public: 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EventData(const FilePath& path, const FilePath::StringType& subdir) 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : path_(path), subdir_(subdir) { } 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FilePath path_; // Full path to this item. 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FilePath::StringType subdir_; // Path to any sub item. 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }; 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) typedef std::vector<struct kevent> EventVector; 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Can only be called on |io_message_loop_|'s thread. 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual void CancelOnMessageLoopThread() OVERRIDE; 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Returns true if the kevent values are error free. 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool AreKeventValuesValid(struct kevent* kevents, int count); 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Respond to a change of attributes of the path component represented by 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // |event|. Sets |target_file_affected| to true if |target_| is affected. 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Sets |update_watches| to true if |events_| need to be updated. 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void HandleAttributesChange(const EventVector::iterator& event, 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool* target_file_affected, 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool* update_watches); 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 97c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Respond to a move or deletion of the path component represented by 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // |event|. Sets |target_file_affected| to true if |target_| is affected. 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Sets |update_watches| to true if |events_| need to be updated. 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void HandleDeleteOrMoveChange(const EventVector::iterator& event, 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool* target_file_affected, 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool* update_watches); 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Respond to a creation of an item in the path component represented by 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // |event|. Sets |target_file_affected| to true if |target_| is affected. 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Sets |update_watches| to true if |events_| need to be updated. 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void HandleCreateItemChange(const EventVector::iterator& event, 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool* target_file_affected, 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool* update_watches); 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Update |events_| with the current status of the system. 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Sets |target_file_affected| to true if |target_| is affected. 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Returns false if an error occurs. 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool UpdateWatches(bool* target_file_affected); 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Fills |events| with one kevent per component in |path|. 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Returns the number of valid events created where a valid event is 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // defined as one that has a ident (file descriptor) field != -1. 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static int EventsForPath(FilePath path, EventVector *events); 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Release a kevent generated by EventsForPath. 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static void ReleaseEvent(struct kevent& event); 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Returns a file descriptor that will not block the system from deleting 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // the file it references. 126c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) static uintptr_t FileDescriptorForPath(const FilePath& path); 127c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 128c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) static const uintptr_t kNoFileDescriptor = static_cast<uintptr_t>(-1); 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Closes |*fd| and sets |*fd| to -1. 131c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) static void CloseFileDescriptor(uintptr_t* fd); 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Returns true if kevent has open file descriptor. 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static bool IsKeventFileDescriptorOpen(const struct kevent& event) { 135c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return event.ident != kNoFileDescriptor; 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static EventData* EventDataForKevent(const struct kevent& event) { 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return reinterpret_cast<EventData*>(event.udata); 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EventVector events_; 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_refptr<base::MessageLoopProxy> io_message_loop_; 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MessageLoopForIO::FileDescriptorWatcher kqueue_watcher_; 1452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) FilePathWatcher::Callback callback_; 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FilePath target_; 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int kqueue_; 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DISALLOW_COPY_AND_ASSIGN(FilePathWatcherImpl); 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void FilePathWatcherImpl::ReleaseEvent(struct kevent& event) { 153c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) CloseFileDescriptor(&event.ident); 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EventData* entry = EventDataForKevent(event); 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) delete entry; 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) event.udata = NULL; 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int FilePathWatcherImpl::EventsForPath(FilePath path, EventVector* events) { 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(MessageLoopForIO::current()); 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Make sure that we are working with a clean slate. 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(events->empty()); 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::vector<FilePath::StringType> components; 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) path.GetComponents(&components); 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (components.size() < 1) { 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return -1; 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int last_existing_entry = 0; 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FilePath built_path; 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool path_still_exists = true; 174a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) for (std::vector<FilePath::StringType>::iterator i = components.begin(); 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) i != components.end(); ++i) { 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (i == components.begin()) { 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) built_path = FilePath(*i); 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) built_path = built_path.Append(*i); 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 181c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) uintptr_t fd = kNoFileDescriptor; 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (path_still_exists) { 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fd = FileDescriptorForPath(built_path); 184c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (fd == kNoFileDescriptor) { 1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) path_still_exists = false; 1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ++last_existing_entry; 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FilePath::StringType subdir = (i != (components.end() - 1)) ? *(i + 1) : ""; 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EventData* data = new EventData(built_path, subdir); 1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct kevent event; 1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EV_SET(&event, fd, EVFILT_VNODE, (EV_ADD | EV_CLEAR | EV_RECEIPT), 1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (NOTE_DELETE | NOTE_WRITE | NOTE_ATTRIB | 1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTE_RENAME | NOTE_REVOKE | NOTE_EXTEND), 0, data); 1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) events->push_back(event); 1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return last_existing_entry; 1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 201c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)uintptr_t FilePathWatcherImpl::FileDescriptorForPath(const FilePath& path) { 202c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) int fd = HANDLE_EINTR(open(path.value().c_str(), O_EVTONLY)); 203c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (fd == -1) 204c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return kNoFileDescriptor; 205c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return fd; 2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 208c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void FilePathWatcherImpl::CloseFileDescriptor(uintptr_t* fd) { 209c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (*fd == kNoFileDescriptor) { 2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 213a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (IGNORE_EINTR(close(*fd)) != 0) { 2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DPLOG(ERROR) << "close"; 2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 216c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) *fd = kNoFileDescriptor; 2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool FilePathWatcherImpl::AreKeventValuesValid(struct kevent* kevents, 2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int count) { 2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (count < 0) { 2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DPLOG(ERROR) << "kevent"; 2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool valid = true; 2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int i = 0; i < count; ++i) { 2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (kevents[i].flags & EV_ERROR && kevents[i].data) { 2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Find the kevent in |events_| that matches the kevent with the error. 2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EventVector::iterator event = events_.begin(); 2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (; event != events_.end(); ++event) { 2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (event->ident == kevents[i].ident) { 2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string path_name; 2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (event != events_.end()) { 2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EventData* event_data = EventDataForKevent(*event); 2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (event_data != NULL) { 2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) path_name = event_data->path_.value(); 2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (path_name.empty()) { 2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) path_name = base::StringPrintf( 244c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) "fd %ld", reinterpret_cast<long>(&kevents[i].ident)); 2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DLOG(ERROR) << "Error: " << kevents[i].data << " for " << path_name; 2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) valid = false; 2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return valid; 2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void FilePathWatcherImpl::HandleAttributesChange( 2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const EventVector::iterator& event, 2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool* target_file_affected, 2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool* update_watches) { 2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EventVector::iterator next_event = event + 1; 2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EventData* next_event_data = EventDataForKevent(*next_event); 2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Check to see if the next item in path is still accessible. 260c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) uintptr_t have_access = FileDescriptorForPath(next_event_data->path_); 261c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (have_access == kNoFileDescriptor) { 2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *target_file_affected = true; 2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *update_watches = true; 2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EventVector::iterator local_event(event); 2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (; local_event != events_.end(); ++local_event) { 2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Close all nodes from the event down. This has the side effect of 2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // potentially rendering other events in |updates| invalid. 2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // There is no need to remove the events from |kqueue_| because this 2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // happens as a side effect of closing the file descriptor. 270c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) CloseFileDescriptor(&local_event->ident); 2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CloseFileDescriptor(&have_access); 2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void FilePathWatcherImpl::HandleDeleteOrMoveChange( 2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const EventVector::iterator& event, 2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool* target_file_affected, 2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool* update_watches) { 2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *target_file_affected = true; 2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *update_watches = true; 2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EventVector::iterator local_event(event); 2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (; local_event != events_.end(); ++local_event) { 2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Close all nodes from the event down. This has the side effect of 2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // potentially rendering other events in |updates| invalid. 2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // There is no need to remove the events from |kqueue_| because this 2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // happens as a side effect of closing the file descriptor. 289c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) CloseFileDescriptor(&local_event->ident); 2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void FilePathWatcherImpl::HandleCreateItemChange( 2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const EventVector::iterator& event, 2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool* target_file_affected, 2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool* update_watches) { 2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Get the next item in the path. 2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EventVector::iterator next_event = event + 1; 2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Check to see if it already has a valid file descriptor. 3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!IsKeventFileDescriptorOpen(*next_event)) { 301c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) EventData* next_event_data = EventDataForKevent(*next_event); 3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If not, attempt to open a file descriptor for it. 3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) next_event->ident = FileDescriptorForPath(next_event_data->path_); 3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (IsKeventFileDescriptorOpen(*next_event)) { 3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *update_watches = true; 3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (next_event_data->subdir_.empty()) { 3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *target_file_affected = true; 3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool FilePathWatcherImpl::UpdateWatches(bool* target_file_affected) { 3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Iterate over events adding kevents for items that exist to the kqueue. 3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Then check to see if new components in the path have been created. 3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Repeat until no new components in the path are detected. 3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This is to get around races in directory creation in a watched path. 3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool update_watches = true; 3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (update_watches) { 3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t valid; 3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (valid = 0; valid < events_.size(); ++valid) { 3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!IsKeventFileDescriptorOpen(events_[valid])) { 3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (valid == 0) { 3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The root of the file path is inaccessible? 3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EventVector updates(valid); 3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int count = HANDLE_EINTR(kevent(kqueue_, &events_[0], valid, &updates[0], 3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) valid, NULL)); 3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!AreKeventValuesValid(&updates[0], count)) { 3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) update_watches = false; 3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (; valid < events_.size(); ++valid) { 3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EventData* event_data = EventDataForKevent(events_[valid]); 3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) events_[valid].ident = FileDescriptorForPath(event_data->path_); 3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (IsKeventFileDescriptorOpen(events_[valid])) { 3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) update_watches = true; 3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (event_data->subdir_.empty()) { 3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *target_file_affected = true; 3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void FilePathWatcherImpl::OnFileCanReadWithoutBlocking(int fd) { 3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(MessageLoopForIO::current()); 3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_EQ(fd, kqueue_); 3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(events_.size()); 3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Request the file system update notifications that have occurred and return 3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // them in |updates|. |count| will contain the number of updates that have 3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // occurred. 3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EventVector updates(events_.size()); 3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct timespec timeout = {0, 0}; 3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int count = HANDLE_EINTR(kevent(kqueue_, NULL, 0, &updates[0], updates.size(), 3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &timeout)); 3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Error values are stored within updates, so check to make sure that no 3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // errors occurred. 3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!AreKeventValuesValid(&updates[0], count)) { 3702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) callback_.Run(target_, true /* error */); 3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Cancel(); 3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool update_watches = false; 3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool send_notification = false; 3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Iterate through each of the updates and react to them. 3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int i = 0; i < count; ++i) { 3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Find our kevent record that matches the update notification. 3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EventVector::iterator event = events_.begin(); 3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (; event != events_.end(); ++event) { 3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!IsKeventFileDescriptorOpen(*event) || 3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) event->ident == updates[i].ident) { 3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 388c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (event == events_.end() || !IsKeventFileDescriptorOpen(*event)) { 3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The event may no longer exist in |events_| because another event 3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // modified |events_| in such a way to make it invalid. For example if 3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // the path is /foo/bar/bam and foo is deleted, NOTE_DELETE events for 3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // foo, bar and bam will be sent. If foo is processed first, then 3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // the file descriptors for bar and bam will already be closed and set 3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // to -1 before they get a chance to be processed. 3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) continue; 3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EventData* event_data = EventDataForKevent(*event); 3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If the subdir is empty, this is the last item on the path and is the 4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // target file. 4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool target_file_affected = event_data->subdir_.empty(); 4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ((updates[i].fflags & NOTE_ATTRIB) && !target_file_affected) { 4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HandleAttributesChange(event, &target_file_affected, &update_watches); 4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (updates[i].fflags & (NOTE_DELETE | NOTE_REVOKE | NOTE_RENAME)) { 4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HandleDeleteOrMoveChange(event, &target_file_affected, &update_watches); 4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ((updates[i].fflags & NOTE_WRITE) && !target_file_affected) { 4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HandleCreateItemChange(event, &target_file_affected, &update_watches); 4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) send_notification |= target_file_affected; 4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (update_watches) { 4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!UpdateWatches(&send_notification)) { 4172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) callback_.Run(target_, true /* error */); 4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Cancel(); 4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (send_notification) { 4232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) callback_.Run(target_, false); 4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void FilePathWatcherImpl::OnFileCanWriteWithoutBlocking(int fd) { 4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED(); 4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void FilePathWatcherImpl::WillDestroyCurrentMessageLoop() { 4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CancelOnMessageLoopThread(); 4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool FilePathWatcherImpl::Watch(const FilePath& path, 4362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) bool recursive, 4372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const FilePathWatcher::Callback& callback) { 4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(MessageLoopForIO::current()); 4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(target_.value().empty()); // Can only watch one path. 4402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(!callback.is_null()); 4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_EQ(kqueue_, -1); 4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (recursive) { 4442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Recursive watch is not supported on this platform. 4452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) NOTIMPLEMENTED(); 4462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return false; 4472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 4482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 4492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) callback_ = callback; 4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) target_ = path; 4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MessageLoop::current()->AddDestructionObserver(this); 4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) io_message_loop_ = base::MessageLoopProxy::current(); 4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kqueue_ = kqueue(); 4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (kqueue_ == -1) { 4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DPLOG(ERROR) << "kqueue"; 4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int last_entry = EventsForPath(target_, &events_); 4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_NE(last_entry, 0); 4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EventVector responses(last_entry); 4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int count = HANDLE_EINTR(kevent(kqueue_, &events_[0], last_entry, 4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &responses[0], last_entry, NULL)); 4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!AreKeventValuesValid(&responses[0], count)) { 4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Calling Cancel() here to close any file descriptors that were opened. 4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This would happen in the destructor anyways, but FilePathWatchers tend to 4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // be long lived, and if an error has occurred, there is no reason to waste 4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // the file descriptors. 4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Cancel(); 4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return MessageLoopForIO::current()->WatchFileDescriptor( 4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kqueue_, true, MessageLoopForIO::WATCH_READ, &kqueue_watcher_, this); 4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void FilePathWatcherImpl::Cancel() { 4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::MessageLoopProxy* proxy = io_message_loop_.get(); 4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!proxy) { 4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) set_cancelled(); 4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!proxy->BelongsToCurrentThread()) { 4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) proxy->PostTask(FROM_HERE, 4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Bind(&FilePathWatcherImpl::Cancel, this)); 4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CancelOnMessageLoopThread(); 4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void FilePathWatcherImpl::CancelOnMessageLoopThread() { 4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(MessageLoopForIO::current()); 4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!is_cancelled()) { 4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) set_cancelled(); 4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kqueue_watcher_.StopWatchingFileDescriptor(); 500a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (IGNORE_EINTR(close(kqueue_)) != 0) { 501c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) DPLOG(ERROR) << "close kqueue"; 502c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 503c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) kqueue_ = -1; 5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::for_each(events_.begin(), events_.end(), ReleaseEvent); 5055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) events_.clear(); 5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) io_message_loop_ = NULL; 5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MessageLoop::current()->RemoveDestructionObserver(this); 5082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) callback_.Reset(); 5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace 5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)FilePathWatcher::FilePathWatcher() { 5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) impl_ = new FilePathWatcherImpl(); 5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace base 519