6
6
#include "run-command.h"
7
7
#include "strbuf.h"
8
8
9
- #define INDEX_EXTENSION_VERSION (1)
10
- #define HOOK_INTERFACE_VERSION (1)
9
+ #define INDEX_EXTENSION_VERSION1 (1)
10
+ #define INDEX_EXTENSION_VERSION2 (2)
11
+ #define HOOK_INTERFACE_VERSION1 (1)
12
+ #define HOOK_INTERFACE_VERSION2 (2)
11
13
12
14
struct trace_key trace_fsmonitor = TRACE_KEY_INIT (FSMONITOR );
13
15
@@ -24,6 +26,22 @@ static void fsmonitor_ewah_callback(size_t pos, void *is)
24
26
ce -> ce_flags &= ~CE_FSMONITOR_VALID ;
25
27
}
26
28
29
+ static int fsmonitor_hook_version (void )
30
+ {
31
+ int hook_version ;
32
+
33
+ if (git_config_get_int ("core.fsmonitorhookversion" , & hook_version ))
34
+ return -1 ;
35
+
36
+ if (hook_version == HOOK_INTERFACE_VERSION1 ||
37
+ hook_version == HOOK_INTERFACE_VERSION2 )
38
+ return hook_version ;
39
+
40
+ warning ("Invalid hook version '%i' in core.fsmonitorhookversion. "
41
+ "Must be 1 or 2." , hook_version );
42
+ return -1 ;
43
+ }
44
+
27
45
int read_fsmonitor_extension (struct index_state * istate , const void * data ,
28
46
unsigned long sz )
29
47
{
@@ -32,17 +50,26 @@ int read_fsmonitor_extension(struct index_state *istate, const void *data,
32
50
uint32_t ewah_size ;
33
51
struct ewah_bitmap * fsmonitor_dirty ;
34
52
int ret ;
53
+ uint64_t timestamp ;
54
+ struct strbuf last_update = STRBUF_INIT ;
35
55
36
- if (sz < sizeof (uint32_t ) + sizeof ( uint64_t ) + sizeof (uint32_t ))
56
+ if (sz < sizeof (uint32_t ) + 1 + sizeof (uint32_t ))
37
57
return error ("corrupt fsmonitor extension (too short)" );
38
58
39
59
hdr_version = get_be32 (index );
40
60
index += sizeof (uint32_t );
41
- if (hdr_version != INDEX_EXTENSION_VERSION )
61
+ if (hdr_version == INDEX_EXTENSION_VERSION1 ) {
62
+ timestamp = get_be64 (index );
63
+ strbuf_addf (& last_update , "%" PRIu64 "" , timestamp );
64
+ index += sizeof (uint64_t );
65
+ } else if (hdr_version == INDEX_EXTENSION_VERSION2 ) {
66
+ strbuf_addstr (& last_update , index );
67
+ index += last_update .len + 1 ;
68
+ } else {
42
69
return error ("bad fsmonitor version %d" , hdr_version );
70
+ }
43
71
44
- istate -> fsmonitor_last_update = get_be64 (index );
45
- index += sizeof (uint64_t );
72
+ istate -> fsmonitor_last_update = strbuf_detach (& last_update , NULL );
46
73
47
74
ewah_size = get_be32 (index );
48
75
index += sizeof (uint32_t );
@@ -79,7 +106,6 @@ void fill_fsmonitor_bitmap(struct index_state *istate)
79
106
void write_fsmonitor_extension (struct strbuf * sb , struct index_state * istate )
80
107
{
81
108
uint32_t hdr_version ;
82
- uint64_t tm ;
83
109
uint32_t ewah_start ;
84
110
uint32_t ewah_size = 0 ;
85
111
int fixup = 0 ;
@@ -89,11 +115,12 @@ void write_fsmonitor_extension(struct strbuf *sb, struct index_state *istate)
89
115
BUG ("fsmonitor_dirty has more entries than the index (%" PRIuMAX " > %u)" ,
90
116
(uintmax_t )istate -> fsmonitor_dirty -> bit_size , istate -> cache_nr );
91
117
92
- put_be32 (& hdr_version , INDEX_EXTENSION_VERSION );
118
+ put_be32 (& hdr_version , INDEX_EXTENSION_VERSION2 );
93
119
strbuf_add (sb , & hdr_version , sizeof (uint32_t ));
94
120
95
- put_be64 (& tm , istate -> fsmonitor_last_update );
96
- strbuf_add (sb , & tm , sizeof (uint64_t ));
121
+ strbuf_addstr (sb , istate -> fsmonitor_last_update );
122
+ strbuf_addch (sb , 0 ); /* Want to keep a NUL */
123
+
97
124
fixup = sb -> len ;
98
125
strbuf_add (sb , & ewah_size , sizeof (uint32_t )); /* we'll fix this up later */
99
126
@@ -110,9 +137,9 @@ void write_fsmonitor_extension(struct strbuf *sb, struct index_state *istate)
110
137
}
111
138
112
139
/*
113
- * Call the query-fsmonitor hook passing the time of the last saved results.
140
+ * Call the query-fsmonitor hook passing the last update token of the saved results.
114
141
*/
115
- static int query_fsmonitor (int version , uint64_t last_update , struct strbuf * query_result )
142
+ static int query_fsmonitor (int version , const char * last_update , struct strbuf * query_result )
116
143
{
117
144
struct child_process cp = CHILD_PROCESS_INIT ;
118
145
@@ -121,7 +148,7 @@ static int query_fsmonitor(int version, uint64_t last_update, struct strbuf *que
121
148
122
149
argv_array_push (& cp .args , core_fsmonitor );
123
150
argv_array_pushf (& cp .args , "%d" , version );
124
- argv_array_pushf (& cp .args , "%" PRIuMAX , ( uintmax_t ) last_update );
151
+ argv_array_pushf (& cp .args , "%s" , last_update );
125
152
cp .use_shell = 1 ;
126
153
cp .dir = get_git_work_tree ();
127
154
@@ -148,14 +175,18 @@ static void fsmonitor_refresh_callback(struct index_state *istate, const char *n
148
175
void refresh_fsmonitor (struct index_state * istate )
149
176
{
150
177
struct strbuf query_result = STRBUF_INIT ;
151
- int query_success = 0 ;
152
- size_t bol ; /* beginning of line */
178
+ int query_success = 0 , hook_version = -1 ;
179
+ size_t bol = 0 ; /* beginning of line */
153
180
uint64_t last_update ;
181
+ struct strbuf last_update_token = STRBUF_INIT ;
154
182
char * buf ;
155
183
unsigned int i ;
156
184
157
185
if (!core_fsmonitor || istate -> fsmonitor_has_run_once )
158
186
return ;
187
+
188
+ hook_version = fsmonitor_hook_version ();
189
+
159
190
istate -> fsmonitor_has_run_once = 1 ;
160
191
161
192
trace_printf_key (& trace_fsmonitor , "refresh fsmonitor" );
@@ -164,26 +195,60 @@ void refresh_fsmonitor(struct index_state *istate)
164
195
* should be inclusive to ensure we don't miss potential changes.
165
196
*/
166
197
last_update = getnanotime ();
198
+ if (hook_version == HOOK_INTERFACE_VERSION1 )
199
+ strbuf_addf (& last_update_token , "%" PRIu64 "" , last_update );
167
200
168
201
/*
169
- * If we have a last update time , call query_fsmonitor for the set of
170
- * changes since that time , else assume everything is possibly dirty
202
+ * If we have a last update token , call query_fsmonitor for the set of
203
+ * changes since that token , else assume everything is possibly dirty
171
204
* and check it all.
172
205
*/
173
206
if (istate -> fsmonitor_last_update ) {
174
- query_success = !query_fsmonitor (HOOK_INTERFACE_VERSION ,
175
- istate -> fsmonitor_last_update , & query_result );
207
+ if (hook_version == -1 || hook_version == HOOK_INTERFACE_VERSION2 ) {
208
+ query_success = !query_fsmonitor (HOOK_INTERFACE_VERSION2 ,
209
+ istate -> fsmonitor_last_update , & query_result );
210
+
211
+ if (query_success ) {
212
+ if (hook_version < 0 )
213
+ hook_version = HOOK_INTERFACE_VERSION2 ;
214
+
215
+ /*
216
+ * First entry will be the last update token
217
+ * Need to use a char * variable because static
218
+ * analysis was suggesting to use strbuf_addbuf
219
+ * but we don't want to copy the entire strbuf
220
+ * only the the chars up to the first NUL
221
+ */
222
+ buf = query_result .buf ;
223
+ strbuf_addstr (& last_update_token , buf );
224
+ if (!last_update_token .len ) {
225
+ warning ("Empty last update token." );
226
+ query_success = 0 ;
227
+ } else {
228
+ bol = last_update_token .len + 1 ;
229
+ }
230
+ } else if (hook_version < 0 ) {
231
+ hook_version = HOOK_INTERFACE_VERSION1 ;
232
+ if (!last_update_token .len )
233
+ strbuf_addf (& last_update_token , "%" PRIu64 "" , last_update );
234
+ }
235
+ }
236
+
237
+ if (hook_version == HOOK_INTERFACE_VERSION1 ) {
238
+ query_success = !query_fsmonitor (HOOK_INTERFACE_VERSION1 ,
239
+ istate -> fsmonitor_last_update , & query_result );
240
+ }
241
+
176
242
trace_performance_since (last_update , "fsmonitor process '%s'" , core_fsmonitor );
177
243
trace_printf_key (& trace_fsmonitor , "fsmonitor process '%s' returned %s" ,
178
244
core_fsmonitor , query_success ? "success" : "failure" );
179
245
}
180
246
181
247
/* a fsmonitor process can return '/' to indicate all entries are invalid */
182
- if (query_success && query_result .buf [0 ] != '/' ) {
248
+ if (query_success && query_result .buf [bol ] != '/' ) {
183
249
/* Mark all entries returned by the monitor as dirty */
184
250
buf = query_result .buf ;
185
- bol = 0 ;
186
- for (i = 0 ; i < query_result .len ; i ++ ) {
251
+ for (i = bol ; i < query_result .len ; i ++ ) {
187
252
if (buf [i ] != '\0' )
188
253
continue ;
189
254
fsmonitor_refresh_callback (istate , buf + bol );
@@ -217,18 +282,21 @@ void refresh_fsmonitor(struct index_state *istate)
217
282
}
218
283
strbuf_release (& query_result );
219
284
220
- /* Now that we've updated istate, save the last_update time */
221
- istate -> fsmonitor_last_update = last_update ;
285
+ /* Now that we've updated istate, save the last_update_token */
286
+ FREE_AND_NULL (istate -> fsmonitor_last_update );
287
+ istate -> fsmonitor_last_update = strbuf_detach (& last_update_token , NULL );
222
288
}
223
289
224
290
void add_fsmonitor (struct index_state * istate )
225
291
{
226
292
unsigned int i ;
293
+ struct strbuf last_update = STRBUF_INIT ;
227
294
228
295
if (!istate -> fsmonitor_last_update ) {
229
296
trace_printf_key (& trace_fsmonitor , "add fsmonitor" );
230
297
istate -> cache_changed |= FSMONITOR_CHANGED ;
231
- istate -> fsmonitor_last_update = getnanotime ();
298
+ strbuf_addf (& last_update , "%" PRIu64 "" , getnanotime ());
299
+ istate -> fsmonitor_last_update = strbuf_detach (& last_update , NULL );
232
300
233
301
/* reset the fsmonitor state */
234
302
for (i = 0 ; i < istate -> cache_nr ; i ++ )
@@ -250,7 +318,7 @@ void remove_fsmonitor(struct index_state *istate)
250
318
if (istate -> fsmonitor_last_update ) {
251
319
trace_printf_key (& trace_fsmonitor , "remove fsmonitor" );
252
320
istate -> cache_changed |= FSMONITOR_CHANGED ;
253
- istate -> fsmonitor_last_update = 0 ;
321
+ FREE_AND_NULL ( istate -> fsmonitor_last_update ) ;
254
322
}
255
323
}
256
324
0 commit comments