| // Copyright 2014 The Chromium Authors | 
 | // Use of this source code is governed by a BSD-style license that can be | 
 | // found in the LICENSE file. | 
 |  | 
 | #ifndef BASE_FILES_FILE_PATH_WATCHER_KQUEUE_H_ | 
 | #define BASE_FILES_FILE_PATH_WATCHER_KQUEUE_H_ | 
 |  | 
 | #include <sys/event.h> | 
 |  | 
 | #include <memory> | 
 | #include <vector> | 
 |  | 
 | #include "base/files/file_descriptor_watcher_posix.h" | 
 | #include "base/files/file_path.h" | 
 | #include "base/files/file_path_watcher.h" | 
 |  | 
 | namespace base { | 
 |  | 
 | // Mac-specific file watcher implementation based on kqueue. | 
 | // The Linux and Windows versions are able to detect: | 
 | // - file creation/deletion/modification in a watched directory | 
 | // - file creation/deletion/modification for a watched file | 
 | // - modifications to the paths to a watched object that would affect the | 
 | //   object such as renaming/attibute changes etc. | 
 | // The kqueue implementation will handle all of the items in the list above | 
 | // except for detecting modifications to files in a watched directory. It will | 
 | // detect the creation and deletion of files, just not the modification of | 
 | // files. It does however detect the attribute changes that the FSEvents impl | 
 | // would miss. | 
 | class FilePathWatcherKQueue : public FilePathWatcher::PlatformDelegate { | 
 |  public: | 
 |   FilePathWatcherKQueue(); | 
 |   FilePathWatcherKQueue(const FilePathWatcherKQueue&) = delete; | 
 |   FilePathWatcherKQueue& operator=(const FilePathWatcherKQueue&) = delete; | 
 |   ~FilePathWatcherKQueue() override; | 
 |  | 
 |   // FilePathWatcher::PlatformDelegate overrides. | 
 |   bool Watch(const FilePath& path, | 
 |              Type type, | 
 |              const FilePathWatcher::Callback& callback) override; | 
 |   void Cancel() override; | 
 |  | 
 |  private: | 
 |   class EventData { | 
 |    public: | 
 |     EventData(const FilePath& path, const FilePath::StringType& subdir) | 
 |         : path_(path), subdir_(subdir) {} | 
 |     FilePath path_;                // Full path to this item. | 
 |     FilePath::StringType subdir_;  // Path to any sub item. | 
 |   }; | 
 |  | 
 |   typedef std::vector<struct kevent> EventVector; | 
 |  | 
 |   // Called when data is available in |kqueue_|. | 
 |   void OnKQueueReadable(); | 
 |  | 
 |   // Returns true if the kevent values are error free. | 
 |   bool AreKeventValuesValid(struct kevent* kevents, int count); | 
 |  | 
 |   // Respond to a change of attributes of the path component represented by | 
 |   // |event|. Sets |target_file_affected| to true if |target_| is affected. | 
 |   // Sets |update_watches| to true if |events_| need to be updated. | 
 |   void HandleAttributesChange(const EventVector::iterator& event, | 
 |                               bool* target_file_affected, | 
 |                               bool* update_watches); | 
 |  | 
 |   // Respond to a move or deletion of the path component represented by | 
 |   // |event|. Sets |target_file_affected| to true if |target_| is affected. | 
 |   // Sets |update_watches| to true if |events_| need to be updated. | 
 |   void HandleDeleteOrMoveChange(const EventVector::iterator& event, | 
 |                                 bool* target_file_affected, | 
 |                                 bool* update_watches); | 
 |  | 
 |   // Respond to a creation of an item in the path component represented by | 
 |   // |event|. Sets |target_file_affected| to true if |target_| is affected. | 
 |   // Sets |update_watches| to true if |events_| need to be updated. | 
 |   void HandleCreateItemChange(const EventVector::iterator& event, | 
 |                               bool* target_file_affected, | 
 |                               bool* update_watches); | 
 |  | 
 |   // Update |events_| with the current status of the system. | 
 |   // Sets |target_file_affected| to true if |target_| is affected. | 
 |   // Returns false if an error occurs. | 
 |   bool UpdateWatches(bool* target_file_affected); | 
 |  | 
 |   // Fills |events| with one kevent per component in |path|. | 
 |   // Returns the number of valid events created where a valid event is | 
 |   // defined as one that has a ident (file descriptor) field != -1. | 
 |   static size_t EventsForPath(FilePath path, EventVector* events); | 
 |  | 
 |   // Fills |events| with one kevent for |path|. Returns 1 if a file descriptor | 
 |   // for |path| could be created, or 0 otherwise. | 
 |   static size_t EventForItem(const FilePath& path, EventVector* events); | 
 |  | 
 |   // Release a kevent generated by EventsForPath. | 
 |   static void ReleaseEvent(struct kevent& event); | 
 |  | 
 |   // Returns a file descriptor that will not block the system from deleting | 
 |   // the file it references. | 
 |   static uintptr_t FileDescriptorForPath(const FilePath& path); | 
 |  | 
 |   static const uintptr_t kNoFileDescriptor = static_cast<uintptr_t>(-1); | 
 |  | 
 |   // Closes |*fd| and sets |*fd| to -1. | 
 |   static void CloseFileDescriptor(uintptr_t* fd); | 
 |  | 
 |   // Returns true if kevent has open file descriptor. | 
 |   static bool IsKeventFileDescriptorOpen(const struct kevent& event) { | 
 |     return event.ident != kNoFileDescriptor; | 
 |   } | 
 |  | 
 |   static EventData* EventDataForKevent(const struct kevent& event) { | 
 |     return reinterpret_cast<EventData*>(event.udata); | 
 |   } | 
 |  | 
 |   EventVector events_; | 
 |   FilePathWatcher::Callback callback_; | 
 |   FilePath target_; | 
 |   int kqueue_; | 
 |  | 
 |   // Throughout the lifetime of this, OnKQueueReadable() will be called when | 
 |   // data is available in |kqueue_|. | 
 |   std::unique_ptr<FileDescriptorWatcher::Controller> kqueue_watch_controller_; | 
 | }; | 
 |  | 
 | }  // namespace base | 
 |  | 
 | #endif  // BASE_FILES_FILE_PATH_WATCHER_KQUEUE_H_ |