1 //===- DirectoryWatcher.h - Listens for directory file changes --*- C++ -*-===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 #ifndef LLVM_CLANG_DIRECTORYWATCHER_DIRECTORYWATCHER_H
10 #define LLVM_CLANG_DIRECTORYWATCHER_DIRECTORYWATCHER_H
12 #include "llvm/ADT/ArrayRef.h"
13 #include "llvm/ADT/StringRef.h"
19 /// Provides notifications for file changes in a directory.
21 /// Invokes client-provided function on every filesystem event in the watched
22 /// directory. Initially the the watched directory is scanned and for every file
23 /// found, an event is synthesized as if the file was added.
25 /// This is not a general purpose directory monitoring tool - list of
26 /// limitations follows.
28 /// Only flat directories with no subdirectories are supported. In case
29 /// subdirectories are present the behavior is unspecified - events *might* be
30 /// passed to Receiver on macOS (due to FSEvents being used) while they
31 /// *probably* won't be passed on Linux (due to inotify being used).
33 /// Known potential inconsistencies
34 /// - For files that are deleted befor the initial scan processed them, clients
35 /// might receive Removed notification without any prior Added notification.
36 /// - Multiple notifications might be produced when a file is added to the
37 /// watched directory during the initial scan. We are choosing the lesser evil
38 /// here as the only known alternative strategy would be to invalidate the
39 /// watcher instance and force user to create a new one whenever filesystem
40 /// event occurs during the initial scan but that would introduce continuous
41 /// restarting failure mode (watched directory is not always "owned" by the same
42 /// process that is consuming it). Since existing clients can handle duplicate
43 /// events well, we decided for simplicity.
45 /// Notifications are provided only for changes done through local user-space
46 /// filesystem interface. Specifically, it's unspecified if notification would
47 /// be provided in case of a:
48 /// - a file mmap-ed and changed
49 /// - a file changed via remote (NFS) or virtual (/proc) FS access to monitored
51 /// - another filesystem mounted to the watched directory
53 /// No support for LLVM VFS.
55 /// It is unspecified whether notifications for files being deleted are sent in
56 /// case the whole watched directory is sent.
58 /// Directories containing "too many" files and/or receiving events "too
59 /// frequently" are not supported - if the initial scan can't be finished before
60 /// the watcher instance gets invalidated (see WatcherGotInvalidated) there's no
61 /// good error handling strategy - the only option for client is to destroy the
62 /// watcher, restart watching with new instance and hope it won't repeat.
63 class DirectoryWatcher {
66 enum class EventKind {
68 /// Content of a file was modified.
70 /// The watched directory got deleted.
72 /// The DirectoryWatcher that originated this event is no longer valid and
73 /// its behavior is unspecified.
75 /// The prime case is kernel signalling to OS-specific implementation of
76 /// DirectoryWatcher some resource limit being hit.
77 /// *Usually* kernel starts dropping or squashing events together after
78 /// that and so would DirectoryWatcher. This means that *some* events
79 /// might still be passed to Receiver but this behavior is unspecified.
81 /// Another case is after the watched directory itself is deleted.
82 /// WatcherGotInvalidated will be received at least once during
83 /// DirectoryWatcher instance lifetime - when handling errors this is done
84 /// on best effort basis, when an instance is being destroyed then this is
87 /// The only proper response to this kind of event is to destruct the
88 /// originating DirectoryWatcher instance and create a new one.
93 /// Filename that this event is related to or an empty string in
94 /// case this event is related to the watched directory itself.
97 Event(EventKind Kind, llvm::StringRef Filename)
98 : Kind(Kind), Filename(Filename) {}
101 /// Returns nullptr if \param Path doesn't exist or isn't a directory.
102 /// Returns nullptr if OS kernel API told us we can't start watching. In such
103 /// case it's unclear whether just retrying has any chance to succeeed.
104 static std::unique_ptr<DirectoryWatcher>
105 create(llvm::StringRef Path,
106 std::function<void(llvm::ArrayRef<DirectoryWatcher::Event> Events,
109 bool WaitForInitialSync);
111 virtual ~DirectoryWatcher() = default;
112 DirectoryWatcher(const DirectoryWatcher &) = delete;
113 DirectoryWatcher &operator=(const DirectoryWatcher &) = delete;
114 DirectoryWatcher(DirectoryWatcher &&) = default;
117 DirectoryWatcher() = default;
122 #endif // LLVM_CLANG_DIRECTORYWATCHER_DIRECTORYWATCHER_H