66#include "run-command.h"
77#include "strbuf.h"
88
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)
1113
1214struct trace_key trace_fsmonitor = TRACE_KEY_INIT (FSMONITOR );
1315
@@ -24,6 +26,22 @@ static void fsmonitor_ewah_callback(size_t pos, void *is)
2426 ce -> ce_flags &= ~CE_FSMONITOR_VALID ;
2527}
2628
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+
2745int read_fsmonitor_extension (struct index_state * istate , const void * data ,
2846 unsigned long sz )
2947{
@@ -32,17 +50,26 @@ int read_fsmonitor_extension(struct index_state *istate, const void *data,
3250 uint32_t ewah_size ;
3351 struct ewah_bitmap * fsmonitor_dirty ;
3452 int ret ;
53+ uint64_t timestamp ;
54+ struct strbuf last_update = STRBUF_INIT ;
3555
36- if (sz < sizeof (uint32_t ) + sizeof ( uint64_t ) + sizeof (uint32_t ))
56+ if (sz < sizeof (uint32_t ) + 1 + sizeof (uint32_t ))
3757 return error ("corrupt fsmonitor extension (too short)" );
3858
3959 hdr_version = get_be32 (index );
4060 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 {
4269 return error ("bad fsmonitor version %d" , hdr_version );
70+ }
4371
44- istate -> fsmonitor_last_update = get_be64 (index );
45- index += sizeof (uint64_t );
72+ istate -> fsmonitor_last_update = strbuf_detach (& last_update , NULL );
4673
4774 ewah_size = get_be32 (index );
4875 index += sizeof (uint32_t );
@@ -79,7 +106,6 @@ void fill_fsmonitor_bitmap(struct index_state *istate)
79106void write_fsmonitor_extension (struct strbuf * sb , struct index_state * istate )
80107{
81108 uint32_t hdr_version ;
82- uint64_t tm ;
83109 uint32_t ewah_start ;
84110 uint32_t ewah_size = 0 ;
85111 int fixup = 0 ;
@@ -89,11 +115,12 @@ void write_fsmonitor_extension(struct strbuf *sb, struct index_state *istate)
89115 BUG ("fsmonitor_dirty has more entries than the index (%" PRIuMAX " > %u)" ,
90116 (uintmax_t )istate -> fsmonitor_dirty -> bit_size , istate -> cache_nr );
91117
92- put_be32 (& hdr_version , INDEX_EXTENSION_VERSION );
118+ put_be32 (& hdr_version , INDEX_EXTENSION_VERSION2 );
93119 strbuf_add (sb , & hdr_version , sizeof (uint32_t ));
94120
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+
97124 fixup = sb -> len ;
98125 strbuf_add (sb , & ewah_size , sizeof (uint32_t )); /* we'll fix this up later */
99126
@@ -110,9 +137,9 @@ void write_fsmonitor_extension(struct strbuf *sb, struct index_state *istate)
110137}
111138
112139/*
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.
114141 */
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 )
116143{
117144 struct child_process cp = CHILD_PROCESS_INIT ;
118145
@@ -121,7 +148,7 @@ static int query_fsmonitor(int version, uint64_t last_update, struct strbuf *que
121148
122149 argv_array_push (& cp .args , core_fsmonitor );
123150 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 );
125152 cp .use_shell = 1 ;
126153 cp .dir = get_git_work_tree ();
127154
@@ -148,14 +175,18 @@ static void fsmonitor_refresh_callback(struct index_state *istate, const char *n
148175void refresh_fsmonitor (struct index_state * istate )
149176{
150177 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 */
153180 uint64_t last_update ;
181+ struct strbuf last_update_token = STRBUF_INIT ;
154182 char * buf ;
155183 unsigned int i ;
156184
157185 if (!core_fsmonitor || istate -> fsmonitor_has_run_once )
158186 return ;
187+
188+ hook_version = fsmonitor_hook_version ();
189+
159190 istate -> fsmonitor_has_run_once = 1 ;
160191
161192 trace_printf_key (& trace_fsmonitor , "refresh fsmonitor" );
@@ -164,26 +195,60 @@ void refresh_fsmonitor(struct index_state *istate)
164195 * should be inclusive to ensure we don't miss potential changes.
165196 */
166197 last_update = getnanotime ();
198+ if (hook_version == HOOK_INTERFACE_VERSION1 )
199+ strbuf_addf (& last_update_token , "%" PRIu64 "" , last_update );
167200
168201 /*
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
171204 * and check it all.
172205 */
173206 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+
176242 trace_performance_since (last_update , "fsmonitor process '%s'" , core_fsmonitor );
177243 trace_printf_key (& trace_fsmonitor , "fsmonitor process '%s' returned %s" ,
178244 core_fsmonitor , query_success ? "success" : "failure" );
179245 }
180246
181247 /* 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 ] != '/' ) {
183249 /* Mark all entries returned by the monitor as dirty */
184250 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 ++ ) {
187252 if (buf [i ] != '\0' )
188253 continue ;
189254 fsmonitor_refresh_callback (istate , buf + bol );
@@ -217,18 +282,21 @@ void refresh_fsmonitor(struct index_state *istate)
217282 }
218283 strbuf_release (& query_result );
219284
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 );
222288}
223289
224290void add_fsmonitor (struct index_state * istate )
225291{
226292 unsigned int i ;
293+ struct strbuf last_update = STRBUF_INIT ;
227294
228295 if (!istate -> fsmonitor_last_update ) {
229296 trace_printf_key (& trace_fsmonitor , "add fsmonitor" );
230297 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 );
232300
233301 /* reset the fsmonitor state */
234302 for (i = 0 ; i < istate -> cache_nr ; i ++ )
@@ -250,7 +318,7 @@ void remove_fsmonitor(struct index_state *istate)
250318 if (istate -> fsmonitor_last_update ) {
251319 trace_printf_key (& trace_fsmonitor , "remove fsmonitor" );
252320 istate -> cache_changed |= FSMONITOR_CHANGED ;
253- istate -> fsmonitor_last_update = 0 ;
321+ FREE_AND_NULL ( istate -> fsmonitor_last_update ) ;
254322 }
255323}
256324
0 commit comments