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