@@ -185,6 +185,26 @@ struct conflict_info {
185185 unsigned match_mask :3 ;
186186};
187187
188+ /*
189+ * For the next three macros, see warning for conflict_info.merged.
190+ *
191+ * In each of the below, mi is a struct merged_info*, and ci was defined
192+ * as a struct conflict_info* (but we need to verify ci isn't actually
193+ * pointed at a struct merged_info*).
194+ *
195+ * INITIALIZE_CI: Assign ci to mi but only if it's safe; set to NULL otherwise.
196+ * VERIFY_CI: Ensure that something we assigned to a conflict_info* is one.
197+ * ASSIGN_AND_VERIFY_CI: Similar to VERIFY_CI but do assignment first.
198+ */
199+ #define INITIALIZE_CI (ci , mi ) do { \
200+ (ci) = (!(mi) || (mi)->clean) ? NULL : (struct conflict_info *)(mi); \
201+ } while (0)
202+ #define VERIFY_CI (ci ) assert(ci && !ci->merged.clean);
203+ #define ASSIGN_AND_VERIFY_CI (ci , mi ) do { \
204+ (ci) = (struct conflict_info *)(mi); \
205+ assert((ci) && !(mi)->clean); \
206+ } while (0)
207+
188208static int err (struct merge_options * opt , const char * err , ...)
189209{
190210 va_list params ;
@@ -201,6 +221,65 @@ static int err(struct merge_options *opt, const char *err, ...)
201221 return -1 ;
202222}
203223
224+ static void setup_path_info (struct merge_options * opt ,
225+ struct string_list_item * result ,
226+ const char * current_dir_name ,
227+ int current_dir_name_len ,
228+ char * fullpath , /* we'll take over ownership */
229+ struct name_entry * names ,
230+ struct name_entry * merged_version ,
231+ unsigned is_null , /* boolean */
232+ unsigned df_conflict , /* boolean */
233+ unsigned filemask ,
234+ unsigned dirmask ,
235+ int resolved /* boolean */ )
236+ {
237+ /* result->util is void*, so mi is a convenience typed variable */
238+ struct merged_info * mi ;
239+
240+ assert (!is_null || resolved );
241+ assert (!df_conflict || !resolved ); /* df_conflict implies !resolved */
242+ assert (resolved == (merged_version != NULL ));
243+
244+ mi = xcalloc (1 , resolved ? sizeof (struct merged_info ) :
245+ sizeof (struct conflict_info ));
246+ mi -> directory_name = current_dir_name ;
247+ mi -> basename_offset = current_dir_name_len ;
248+ mi -> clean = !!resolved ;
249+ if (resolved ) {
250+ mi -> result .mode = merged_version -> mode ;
251+ oidcpy (& mi -> result .oid , & merged_version -> oid );
252+ mi -> is_null = !!is_null ;
253+ } else {
254+ int i ;
255+ struct conflict_info * ci ;
256+
257+ ASSIGN_AND_VERIFY_CI (ci , mi );
258+ for (i = MERGE_BASE ; i <= MERGE_SIDE2 ; i ++ ) {
259+ ci -> pathnames [i ] = fullpath ;
260+ ci -> stages [i ].mode = names [i ].mode ;
261+ oidcpy (& ci -> stages [i ].oid , & names [i ].oid );
262+ }
263+ ci -> filemask = filemask ;
264+ ci -> dirmask = dirmask ;
265+ ci -> df_conflict = !!df_conflict ;
266+ if (dirmask )
267+ /*
268+ * Assume is_null for now, but if we have entries
269+ * under the directory then when it is complete in
270+ * write_completed_directory() it'll update this.
271+ * Also, for D/F conflicts, we have to handle the
272+ * directory first, then clear this bit and process
273+ * the file to see how it is handled -- that occurs
274+ * near the top of process_entry().
275+ */
276+ mi -> is_null = 1 ;
277+ }
278+ strmap_put (& opt -> priv -> paths , fullpath , mi );
279+ result -> string = fullpath ;
280+ result -> util = mi ;
281+ }
282+
204283static int collect_merge_info_callback (int n ,
205284 unsigned long mask ,
206285 unsigned long dirmask ,
@@ -215,10 +294,12 @@ static int collect_merge_info_callback(int n,
215294 */
216295 struct merge_options * opt = info -> data ;
217296 struct merge_options_internal * opti = opt -> priv ;
218- struct conflict_info * ci ;
297+ struct string_list_item pi ; /* Path Info */
298+ struct conflict_info * ci ; /* typed alias to pi.util (which is void*) */
219299 struct name_entry * p ;
220300 size_t len ;
221301 char * fullpath ;
302+ const char * dirname = opti -> current_dir_name ;
222303 unsigned filemask = mask & ~dirmask ;
223304 unsigned match_mask = 0 ; /* will be updated below */
224305 unsigned mbase_null = !(mask & 1 );
@@ -287,13 +368,15 @@ static int collect_merge_info_callback(int n,
287368 make_traverse_path (fullpath , len + 1 , info , p -> path , p -> pathlen );
288369
289370 /*
290- * TODO: record information about the path other than all zeros,
291- * so we can resolve later in process_entries.
371+ * Record information about the path so we can resolve later in
372+ * process_entries.
292373 */
293- ci = xcalloc (1 , sizeof (struct conflict_info ));
294- ci -> df_conflict = df_conflict ;
374+ setup_path_info (opt , & pi , dirname , info -> pathlen , fullpath ,
375+ names , NULL , 0 , df_conflict , filemask , dirmask , 0 );
376+
377+ ci = pi .util ;
378+ VERIFY_CI (ci );
295379 ci -> match_mask = match_mask ;
296- strmap_put (& opti -> paths , fullpath , ci );
297380
298381 /* If dirmask, recurse into subdirectories */
299382 if (dirmask ) {
@@ -337,7 +420,7 @@ static int collect_merge_info_callback(int n,
337420 }
338421
339422 original_dir_name = opti -> current_dir_name ;
340- opti -> current_dir_name = fullpath ;
423+ opti -> current_dir_name = pi . string ;
341424 ret = traverse_trees (NULL , 3 , t , & newinfo );
342425 opti -> current_dir_name = original_dir_name ;
343426
0 commit comments