1
+#include "cache.h"
2
+#include "config.h"
3
+#include "dir.h"
4
+#include "ewah/ewok.h"
5
+#include "fsmonitor.h"
6
+#include "run-command.h"
7
+#include "strbuf.h"
8
+
9
+#define INDEX_EXTENSION_VERSION (1)
10
+#define HOOK_INTERFACE_VERSION (1)
11
+
12
+struct trace_key trace_fsmonitor = TRACE_KEY_INIT(FSMONITOR);
13
+
14
+static void fsmonitor_ewah_callback(size_t pos, void *is)
15
+{
16
+ struct index_state *istate = (struct index_state *)is;
17
+ struct cache_entry *ce = istate->cache[pos];
18
+
19
+ ce->ce_flags &= ~CE_FSMONITOR_VALID;
20
+}
21
+
22
+int read_fsmonitor_extension(struct index_state *istate, const void *data,
23
+ unsigned long sz)
24
+{
25
+ const char *index = data;
26
+ uint32_t hdr_version;
27
+ uint32_t ewah_size;
28
+ struct ewah_bitmap *fsmonitor_dirty;
29
+ int i;
30
+ int ret;
31
+
32
+ if (sz < sizeof(uint32_t) + sizeof(uint64_t) + sizeof(uint32_t))
33
+ return error("corrupt fsmonitor extension (too short)");
34
+
35
+ hdr_version = get_be32(index);
36
+ index += sizeof(uint32_t);
37
+ if (hdr_version != INDEX_EXTENSION_VERSION)
38
+ return error("bad fsmonitor version %d", hdr_version);
39
+
40
+ istate->fsmonitor_last_update = get_be64(index);
41
+ index += sizeof(uint64_t);
42
+
43
+ ewah_size = get_be32(index);
44
+ index += sizeof(uint32_t);
45
+
46
+ fsmonitor_dirty = ewah_new();
47
+ ret = ewah_read_mmap(fsmonitor_dirty, index, ewah_size);
48
+ if (ret != ewah_size) {
49
+ ewah_free(fsmonitor_dirty);
50
+ return error("failed to parse ewah bitmap reading fsmonitor index extension");
51
+ }
52
+
53
+ if (git_config_get_fsmonitor()) {
54
+ /* Mark all entries valid */
55
+ for (i = 0; i < istate->cache_nr; i++)
56
+ istate->cache[i]->ce_flags |= CE_FSMONITOR_VALID;
57
+
58
+ /* Mark all previously saved entries as dirty */
59
+ ewah_each_bit(fsmonitor_dirty, fsmonitor_ewah_callback, istate);
60
+
61
+ /* Now mark the untracked cache for fsmonitor usage */
62
+ if (istate->untracked)
63
+ istate->untracked->use_fsmonitor = 1;
64
+ }
65
+ ewah_free(fsmonitor_dirty);
66
+
67
+ trace_printf_key(&trace_fsmonitor, "read fsmonitor extension successful");
68
+ return 0;
69
+}
70
+
71
+void write_fsmonitor_extension(struct strbuf *sb, struct index_state *istate)
72
+{
73
+ uint32_t hdr_version;
74
+ uint64_t tm;
75
+ struct ewah_bitmap *bitmap;
76
+ int i;
77
+ uint32_t ewah_start;
78
+ uint32_t ewah_size = 0;
79
+ int fixup = 0;
80
+
81
+ put_be32(&hdr_version, INDEX_EXTENSION_VERSION);
82
+ strbuf_add(sb, &hdr_version, sizeof(uint32_t));
83
+
84
+ put_be64(&tm, istate->fsmonitor_last_update);
85
+ strbuf_add(sb, &tm, sizeof(uint64_t));
86
+ fixup = sb->len;
87
+ strbuf_add(sb, &ewah_size, sizeof(uint32_t)); /* we'll fix this up later */
88
+
89
+ ewah_start = sb->len;
90
+ bitmap = ewah_new();
91
+ for (i = 0; i < istate->cache_nr; i++)
92
+ if (!(istate->cache[i]->ce_flags & CE_FSMONITOR_VALID))
93
+ ewah_set(bitmap, i);
94
+ ewah_serialize_strbuf(bitmap, sb);
95
+ ewah_free(bitmap);
96
+
97
+ /* fix up size field */
98
+ put_be32(&ewah_size, sb->len - ewah_start);
99
+ memcpy(sb->buf + fixup, &ewah_size, sizeof(uint32_t));
100
+
101
+ trace_printf_key(&trace_fsmonitor, "write fsmonitor extension successful");
102
+}
103
+
104
+/*
105
+ * Call the query-fsmonitor hook passing the time of the last saved results.
106
+ */
107
+static int query_fsmonitor(int version, uint64_t last_update, struct strbuf *query_result)
108
+{
109
+ struct child_process cp = CHILD_PROCESS_INIT;
110
+ char ver[64];
111
+ char date[64];
112
+ const char *argv[4];
113
+
114
+ if (!(argv[0] = core_fsmonitor))
115
+ return -1;
116
+
117
+ snprintf(ver, sizeof(version), "%d", version);
118
+ snprintf(date, sizeof(date), "%" PRIuMAX, (uintmax_t)last_update);
119
+ argv[1] = ver;
120
+ argv[2] = date;
121
+ argv[3] = NULL;
122
+ cp.argv = argv;
123
+ cp.use_shell = 1;
124
+
125
+ return capture_command(&cp, query_result, 1024);
126
+}
127
+
128
+static void fsmonitor_refresh_callback(struct index_state *istate, const char *name)
129
+{
130
+ int pos = index_name_pos(istate, name, strlen(name));
131
+
132
+ if (pos >= 0) {
133
+ struct cache_entry *ce = istate->cache[pos];
134
+ ce->ce_flags &= ~CE_FSMONITOR_VALID;
135
+ }
136
+
137
+ /*
138
+ * Mark the untracked cache dirty even if it wasn't found in the index
139
+ * as it could be a new untracked file.
140
+ */
141
+ trace_printf_key(&trace_fsmonitor, "fsmonitor_refresh_callback '%s'", name);
142
+ untracked_cache_invalidate_path(istate, name);
143
+}
144
+
145
+void refresh_fsmonitor(struct index_state *istate)
146
+{
147
+ static int has_run_once = 0;
148
+ struct strbuf query_result = STRBUF_INIT;
149
+ int query_success = 0;
150
+ size_t bol; /* beginning of line */
151
+ uint64_t last_update;
152
+ char *buf;
153
+ int i;
154
+
155
+ if (!core_fsmonitor || has_run_once)
156
+ return;
157
+ has_run_once = 1;
158
+
159
+ trace_printf_key(&trace_fsmonitor, "refresh fsmonitor");
160
+ /*
161
+ * This could be racy so save the date/time now and query_fsmonitor
162
+ * should be inclusive to ensure we don't miss potential changes.
163
+ */
164
+ last_update = getnanotime();
165
+
166
+ /*
167
+ * If we have a last update time, call query_fsmonitor for the set of
168
+ * changes since that time, else assume everything is possibly dirty
169
+ * and check it all.
170
+ */
171
+ if (istate->fsmonitor_last_update) {
172
+ query_success = !query_fsmonitor(HOOK_INTERFACE_VERSION,
173
+ istate->fsmonitor_last_update, &query_result);
174
+ trace_performance_since(last_update, "fsmonitor process '%s'", core_fsmonitor);
175
+ trace_printf_key(&trace_fsmonitor, "fsmonitor process '%s' returned %s",
176
+ core_fsmonitor, query_success ? "success" : "failure");
177
+ }
178
+
179
+ /* a fsmonitor process can return '/' to indicate all entries are invalid */
180
+ if (query_success && query_result.buf[0] != '/') {
181
+ /* Mark all entries returned by the monitor as dirty */
182
+ buf = query_result.buf;
183
+ bol = 0;
184
+ for (i = 0; i < query_result.len; i++) {
185
+ if (buf[i] != '\0')
186
+ continue;
187
+ fsmonitor_refresh_callback(istate, buf + bol);
188
+ bol = i + 1;
189
+ }
190
+ if (bol < query_result.len)
191
+ fsmonitor_refresh_callback(istate, buf + bol);
192
+ } else {
193
+ /* Mark all entries invalid */
194
+ for (i = 0; i < istate->cache_nr; i++)
195
+ istate->cache[i]->ce_flags &= ~CE_FSMONITOR_VALID;
196
+
197
+ if (istate->untracked)
198
+ istate->untracked->use_fsmonitor = 0;
199
+ }
200
+ strbuf_release(&query_result);
201
+
202
+ /* Now that we've updated istate, save the last_update time */
203
+ istate->fsmonitor_last_update = last_update;
204
+}
205
+
206
+void add_fsmonitor(struct index_state *istate)
207
+{
208
+ int i;
209
+
210
+ if (!istate->fsmonitor_last_update) {
211
+ trace_printf_key(&trace_fsmonitor, "add fsmonitor");
212
+ istate->cache_changed |= FSMONITOR_CHANGED;
213
+ istate->fsmonitor_last_update = getnanotime();
214
+
215
+ /* reset the fsmonitor state */
216
+ for (i = 0; i < istate->cache_nr; i++)
217
+ istate->cache[i]->ce_flags &= ~CE_FSMONITOR_VALID;
218
+
219
+ /* reset the untracked cache */
220
+ if (istate->untracked) {
221
+ add_untracked_cache(istate);
222
+ istate->untracked->use_fsmonitor = 1;
223
+ }
224
+
225
+ /* Update the fsmonitor state */
226
+ refresh_fsmonitor(istate);
227
+ }
228
+}
229
+
230
+void remove_fsmonitor(struct index_state *istate)
231
+{
232
+ if (istate->fsmonitor_last_update) {
233
+ trace_printf_key(&trace_fsmonitor, "remove fsmonitor");
234
+ istate->cache_changed |= FSMONITOR_CHANGED;
235
+ istate->fsmonitor_last_update = 0;
236
+ }
237
+}
238
+
239
+void tweak_fsmonitor(struct index_state *istate)
240
+{
241
+ switch (git_config_get_fsmonitor()) {
242
+ case -1: /* keep: do nothing */
243
+ break;
244
+ case 0: /* false */
245
+ remove_fsmonitor(istate);
246
+ break;
247
+ case 1: /* true */
248
+ add_fsmonitor(istate);
249
+ break;
250
+ default: /* unknown value: do nothing */
251
+ break;
252
+ }
253
+}