1 // Copyright 2014 The Chromium Authors 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef BASE_FILES_FILE_PATH_WATCHER_KQUEUE_H_ 6 #define BASE_FILES_FILE_PATH_WATCHER_KQUEUE_H_ 7 8 #include <sys/event.h> 9 10 #include <memory> 11 #include <vector> 12 13 #include "base/files/file_descriptor_watcher_posix.h" 14 #include "base/files/file_path.h" 15 #include "base/files/file_path_watcher.h" 16 17 namespace base { 18 19 // Mac-specific file watcher implementation based on kqueue. 20 // The Linux and Windows versions are able to detect: 21 // - file creation/deletion/modification in a watched directory 22 // - file creation/deletion/modification for a watched file 23 // - modifications to the paths to a watched object that would affect the 24 // object such as renaming/attibute changes etc. 25 // The kqueue implementation will handle all of the items in the list above 26 // except for detecting modifications to files in a watched directory. It will 27 // detect the creation and deletion of files, just not the modification of 28 // files. It does however detect the attribute changes that the FSEvents impl 29 // would miss. 30 class FilePathWatcherKQueue : public FilePathWatcher::PlatformDelegate { 31 public: 32 FilePathWatcherKQueue(); 33 FilePathWatcherKQueue(const FilePathWatcherKQueue&) = delete; 34 FilePathWatcherKQueue& operator=(const FilePathWatcherKQueue&) = delete; 35 ~FilePathWatcherKQueue() override; 36 37 // FilePathWatcher::PlatformDelegate overrides. 38 bool Watch(const FilePath& path, 39 Type type, 40 const FilePathWatcher::Callback& callback) override; 41 void Cancel() override; 42 43 private: 44 class EventData { 45 public: EventData(const FilePath & path,const FilePath::StringType & subdir)46 EventData(const FilePath& path, const FilePath::StringType& subdir) 47 : path_(path), subdir_(subdir) { } 48 FilePath path_; // Full path to this item. 49 FilePath::StringType subdir_; // Path to any sub item. 50 }; 51 52 typedef std::vector<struct kevent> EventVector; 53 54 // Called when data is available in |kqueue_|. 55 void OnKQueueReadable(); 56 57 // Returns true if the kevent values are error free. 58 bool AreKeventValuesValid(struct kevent* kevents, int count); 59 60 // Respond to a change of attributes of the path component represented by 61 // |event|. Sets |target_file_affected| to true if |target_| is affected. 62 // Sets |update_watches| to true if |events_| need to be updated. 63 void HandleAttributesChange(const EventVector::iterator& event, 64 bool* target_file_affected, 65 bool* update_watches); 66 67 // Respond to a move or deletion of the path component represented by 68 // |event|. Sets |target_file_affected| to true if |target_| is affected. 69 // Sets |update_watches| to true if |events_| need to be updated. 70 void HandleDeleteOrMoveChange(const EventVector::iterator& event, 71 bool* target_file_affected, 72 bool* update_watches); 73 74 // Respond to a creation of an item in the path component represented by 75 // |event|. Sets |target_file_affected| to true if |target_| is affected. 76 // Sets |update_watches| to true if |events_| need to be updated. 77 void HandleCreateItemChange(const EventVector::iterator& event, 78 bool* target_file_affected, 79 bool* update_watches); 80 81 // Update |events_| with the current status of the system. 82 // Sets |target_file_affected| to true if |target_| is affected. 83 // Returns false if an error occurs. 84 bool UpdateWatches(bool* target_file_affected); 85 86 // Fills |events| with one kevent per component in |path|. 87 // Returns the number of valid events created where a valid event is 88 // defined as one that has a ident (file descriptor) field != -1. 89 static size_t EventsForPath(FilePath path, EventVector* events); 90 91 // Fills |events| with one kevent for |path|. Returns 1 if a file descriptor 92 // for |path| could be created, or 0 otherwise. 93 static size_t EventForItem(const FilePath& path, EventVector* events); 94 95 // Release a kevent generated by EventsForPath. 96 static void ReleaseEvent(struct kevent& event); 97 98 // Returns a file descriptor that will not block the system from deleting 99 // the file it references. 100 static uintptr_t FileDescriptorForPath(const FilePath& path); 101 102 static const uintptr_t kNoFileDescriptor = static_cast<uintptr_t>(-1); 103 104 // Closes |*fd| and sets |*fd| to -1. 105 static void CloseFileDescriptor(uintptr_t* fd); 106 107 // Returns true if kevent has open file descriptor. IsKeventFileDescriptorOpen(const struct kevent & event)108 static bool IsKeventFileDescriptorOpen(const struct kevent& event) { 109 return event.ident != kNoFileDescriptor; 110 } 111 EventDataForKevent(const struct kevent & event)112 static EventData* EventDataForKevent(const struct kevent& event) { 113 return reinterpret_cast<EventData*>(event.udata); 114 } 115 116 EventVector events_; 117 FilePathWatcher::Callback callback_; 118 FilePath target_; 119 int kqueue_; 120 121 // Throughout the lifetime of this, OnKQueueReadable() will be called when 122 // data is available in |kqueue_|. 123 std::unique_ptr<FileDescriptorWatcher::Controller> kqueue_watch_controller_; 124 }; 125 126 } // namespace base 127 128 #endif // BASE_FILES_FILE_PATH_WATCHER_KQUEUE_H_ 129