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