t5520: improve test style
[git] / fsmonitor.c
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;
18
19         if (pos >= istate->cache_nr)
20                 BUG("fsmonitor_dirty has more entries than the index (%"PRIuMAX" >= %u)",
21                     (uintmax_t)pos, istate->cache_nr);
22
23         ce = istate->cache[pos];
24         ce->ce_flags &= ~CE_FSMONITOR_VALID;
25 }
26
27 int read_fsmonitor_extension(struct index_state *istate, const void *data,
28         unsigned long sz)
29 {
30         const char *index = data;
31         uint32_t hdr_version;
32         uint32_t ewah_size;
33         struct ewah_bitmap *fsmonitor_dirty;
34         int ret;
35
36         if (sz < sizeof(uint32_t) + sizeof(uint64_t) + sizeof(uint32_t))
37                 return error("corrupt fsmonitor extension (too short)");
38
39         hdr_version = get_be32(index);
40         index += sizeof(uint32_t);
41         if (hdr_version != INDEX_EXTENSION_VERSION)
42                 return error("bad fsmonitor version %d", hdr_version);
43
44         istate->fsmonitor_last_update = get_be64(index);
45         index += sizeof(uint64_t);
46
47         ewah_size = get_be32(index);
48         index += sizeof(uint32_t);
49
50         fsmonitor_dirty = ewah_new();
51         ret = ewah_read_mmap(fsmonitor_dirty, index, ewah_size);
52         if (ret != ewah_size) {
53                 ewah_free(fsmonitor_dirty);
54                 return error("failed to parse ewah bitmap reading fsmonitor index extension");
55         }
56         istate->fsmonitor_dirty = fsmonitor_dirty;
57
58         if (istate->fsmonitor_dirty->bit_size > istate->cache_nr)
59                 BUG("fsmonitor_dirty has more entries than the index (%"PRIuMAX" > %u)",
60                     (uintmax_t)istate->fsmonitor_dirty->bit_size, istate->cache_nr);
61
62         trace_printf_key(&trace_fsmonitor, "read fsmonitor extension successful");
63         return 0;
64 }
65
66 void fill_fsmonitor_bitmap(struct index_state *istate)
67 {
68         unsigned int i, skipped = 0;
69         istate->fsmonitor_dirty = ewah_new();
70         for (i = 0; i < istate->cache_nr; i++) {
71                 if (istate->cache[i]->ce_flags & CE_REMOVE)
72                         skipped++;
73                 else if (!(istate->cache[i]->ce_flags & CE_FSMONITOR_VALID))
74                         ewah_set(istate->fsmonitor_dirty, i - skipped);
75         }
76 }
77
78 void write_fsmonitor_extension(struct strbuf *sb, struct index_state *istate)
79 {
80         uint32_t hdr_version;
81         uint64_t tm;
82         uint32_t ewah_start;
83         uint32_t ewah_size = 0;
84         int fixup = 0;
85
86         if (istate->fsmonitor_dirty->bit_size > istate->cache_nr)
87                 BUG("fsmonitor_dirty has more entries than the index (%"PRIuMAX" > %u)",
88                     (uintmax_t)istate->fsmonitor_dirty->bit_size, istate->cache_nr);
89
90         put_be32(&hdr_version, INDEX_EXTENSION_VERSION);
91         strbuf_add(sb, &hdr_version, sizeof(uint32_t));
92
93         put_be64(&tm, istate->fsmonitor_last_update);
94         strbuf_add(sb, &tm, sizeof(uint64_t));
95         fixup = sb->len;
96         strbuf_add(sb, &ewah_size, sizeof(uint32_t)); /* we'll fix this up later */
97
98         ewah_start = sb->len;
99         ewah_serialize_strbuf(istate->fsmonitor_dirty, sb);
100         ewah_free(istate->fsmonitor_dirty);
101         istate->fsmonitor_dirty = NULL;
102
103         /* fix up size field */
104         put_be32(&ewah_size, sb->len - ewah_start);
105         memcpy(sb->buf + fixup, &ewah_size, sizeof(uint32_t));
106
107         trace_printf_key(&trace_fsmonitor, "write fsmonitor extension successful");
108 }
109
110 /*
111  * Call the query-fsmonitor hook passing the time of the last saved results.
112  */
113 static int query_fsmonitor(int version, uint64_t last_update, struct strbuf *query_result)
114 {
115         struct child_process cp = CHILD_PROCESS_INIT;
116
117         if (!core_fsmonitor)
118                 return -1;
119
120         argv_array_push(&cp.args, core_fsmonitor);
121         argv_array_pushf(&cp.args, "%d", version);
122         argv_array_pushf(&cp.args, "%" PRIuMAX, (uintmax_t)last_update);
123         cp.use_shell = 1;
124         cp.dir = get_git_work_tree();
125
126         return capture_command(&cp, query_result, 1024);
127 }
128
129 static void fsmonitor_refresh_callback(struct index_state *istate, const char *name)
130 {
131         int pos = index_name_pos(istate, name, strlen(name));
132
133         if (pos >= 0) {
134                 struct cache_entry *ce = istate->cache[pos];
135                 ce->ce_flags &= ~CE_FSMONITOR_VALID;
136         }
137
138         /*
139          * Mark the untracked cache dirty even if it wasn't found in the index
140          * as it could be a new untracked file.
141          */
142         trace_printf_key(&trace_fsmonitor, "fsmonitor_refresh_callback '%s'", name);
143         untracked_cache_invalidate_path(istate, name, 0);
144 }
145
146 void refresh_fsmonitor(struct index_state *istate)
147 {
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         unsigned int i;
154
155         if (!core_fsmonitor || istate->fsmonitor_has_run_once)
156                 return;
157         istate->fsmonitor_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 we're going to check every file, ensure we save the results */
198                 istate->cache_changed |= FSMONITOR_CHANGED;
199
200                 if (istate->untracked)
201                         istate->untracked->use_fsmonitor = 0;
202         }
203         strbuf_release(&query_result);
204
205         /* Now that we've updated istate, save the last_update time */
206         istate->fsmonitor_last_update = last_update;
207 }
208
209 void add_fsmonitor(struct index_state *istate)
210 {
211         unsigned int i;
212
213         if (!istate->fsmonitor_last_update) {
214                 trace_printf_key(&trace_fsmonitor, "add fsmonitor");
215                 istate->cache_changed |= FSMONITOR_CHANGED;
216                 istate->fsmonitor_last_update = getnanotime();
217
218                 /* reset the fsmonitor state */
219                 for (i = 0; i < istate->cache_nr; i++)
220                         istate->cache[i]->ce_flags &= ~CE_FSMONITOR_VALID;
221
222                 /* reset the untracked cache */
223                 if (istate->untracked) {
224                         add_untracked_cache(istate);
225                         istate->untracked->use_fsmonitor = 1;
226                 }
227
228                 /* Update the fsmonitor state */
229                 refresh_fsmonitor(istate);
230         }
231 }
232
233 void remove_fsmonitor(struct index_state *istate)
234 {
235         if (istate->fsmonitor_last_update) {
236                 trace_printf_key(&trace_fsmonitor, "remove fsmonitor");
237                 istate->cache_changed |= FSMONITOR_CHANGED;
238                 istate->fsmonitor_last_update = 0;
239         }
240 }
241
242 void tweak_fsmonitor(struct index_state *istate)
243 {
244         unsigned int i;
245         int fsmonitor_enabled = git_config_get_fsmonitor();
246
247         if (istate->fsmonitor_dirty) {
248                 if (fsmonitor_enabled) {
249                         /* Mark all entries valid */
250                         for (i = 0; i < istate->cache_nr; i++) {
251                                 istate->cache[i]->ce_flags |= CE_FSMONITOR_VALID;
252                         }
253
254                         /* Mark all previously saved entries as dirty */
255                         if (istate->fsmonitor_dirty->bit_size > istate->cache_nr)
256                                 BUG("fsmonitor_dirty has more entries than the index (%"PRIuMAX" > %u)",
257                                     (uintmax_t)istate->fsmonitor_dirty->bit_size, istate->cache_nr);
258                         ewah_each_bit(istate->fsmonitor_dirty, fsmonitor_ewah_callback, istate);
259
260                         /* Now mark the untracked cache for fsmonitor usage */
261                         if (istate->untracked)
262                                 istate->untracked->use_fsmonitor = 1;
263                 }
264
265                 ewah_free(istate->fsmonitor_dirty);
266                 istate->fsmonitor_dirty = NULL;
267         }
268
269         switch (fsmonitor_enabled) {
270         case -1: /* keep: do nothing */
271                 break;
272         case 0: /* false */
273                 remove_fsmonitor(istate);
274                 break;
275         case 1: /* true */
276                 add_fsmonitor(istate);
277                 break;
278         default: /* unknown value: do nothing */
279                 break;
280         }
281 }