@@ -252,16 +252,6 @@ static void changed_files(struct hashmap *result, const char *index_path,
252
252
strbuf_release (& buf );
253
253
}
254
254
255
- static NORETURN void exit_cleanup (const char * tmpdir , int exit_code )
256
- {
257
- struct strbuf buf = STRBUF_INIT ;
258
- strbuf_addstr (& buf , tmpdir );
259
- remove_dir_recursively (& buf , 0 );
260
- if (exit_code )
261
- warning (_ ("failed: %d" ), exit_code );
262
- exit (exit_code );
263
- }
264
-
265
255
static int ensure_leading_directories (char * path )
266
256
{
267
257
switch (safe_create_leading_directories (path )) {
@@ -330,19 +320,44 @@ static int checkout_path(unsigned mode, struct object_id *oid,
330
320
return ret ;
331
321
}
332
322
323
+ static void write_file_in_directory (struct strbuf * dir , size_t dir_len ,
324
+ const char * path , const char * content )
325
+ {
326
+ add_path (dir , dir_len , path );
327
+ ensure_leading_directories (dir -> buf );
328
+ unlink (dir -> buf );
329
+ write_file (dir -> buf , "%s" , content );
330
+ }
331
+
332
+ /* Write the file contents for the left and right sides of the difftool
333
+ * dir-diff representation for submodules and symlinks. Symlinks and submodules
334
+ * are written as regular text files so that external diff tools can diff them
335
+ * as text files, resulting in behavior that is analogous to to what "git diff"
336
+ * displays for symlink and submodule diffs.
337
+ */
338
+ static void write_standin_files (struct pair_entry * entry ,
339
+ struct strbuf * ldir , size_t ldir_len ,
340
+ struct strbuf * rdir , size_t rdir_len )
341
+ {
342
+ if (* entry -> left )
343
+ write_file_in_directory (ldir , ldir_len , entry -> path , entry -> left );
344
+ if (* entry -> right )
345
+ write_file_in_directory (rdir , rdir_len , entry -> path , entry -> right );
346
+ }
347
+
333
348
static int run_dir_diff (const char * extcmd , int symlinks , const char * prefix ,
334
349
struct child_process * child )
335
350
{
336
- char tmpdir [PATH_MAX ];
337
351
struct strbuf info = STRBUF_INIT , lpath = STRBUF_INIT ;
338
352
struct strbuf rpath = STRBUF_INIT , buf = STRBUF_INIT ;
339
353
struct strbuf ldir = STRBUF_INIT , rdir = STRBUF_INIT ;
340
354
struct strbuf wtdir = STRBUF_INIT ;
341
- char * lbase_dir , * rbase_dir ;
355
+ struct strbuf tmpdir = STRBUF_INIT ;
356
+ char * lbase_dir = NULL , * rbase_dir = NULL ;
342
357
size_t ldir_len , rdir_len , wtdir_len ;
343
358
const char * workdir , * tmp ;
344
359
int ret = 0 , i ;
345
- FILE * fp ;
360
+ FILE * fp = NULL ;
346
361
struct hashmap working_tree_dups = HASHMAP_INIT (working_tree_entry_cmp ,
347
362
NULL );
348
363
struct hashmap submodules = HASHMAP_INIT (pair_cmp , NULL );
@@ -351,7 +366,7 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,
351
366
struct pair_entry * entry ;
352
367
struct index_state wtindex ;
353
368
struct checkout lstate , rstate ;
354
- int rc , flags = RUN_GIT_CMD , err = 0 ;
369
+ int flags = RUN_GIT_CMD , err = 0 ;
355
370
const char * helper_argv [] = { "difftool--helper" , NULL , NULL , NULL };
356
371
struct hashmap wt_modified , tmp_modified ;
357
372
int indices_loaded = 0 ;
@@ -360,11 +375,15 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,
360
375
361
376
/* Setup temp directories */
362
377
tmp = getenv ("TMPDIR" );
363
- xsnprintf (tmpdir , sizeof (tmpdir ), "%s/git-difftool.XXXXXX" , tmp ? tmp : "/tmp" );
364
- if (!mkdtemp (tmpdir ))
365
- return error ("could not create '%s'" , tmpdir );
366
- strbuf_addf (& ldir , "%s/left/" , tmpdir );
367
- strbuf_addf (& rdir , "%s/right/" , tmpdir );
378
+ strbuf_add_absolute_path (& tmpdir , tmp ? tmp : "/tmp" );
379
+ strbuf_trim_trailing_dir_sep (& tmpdir );
380
+ strbuf_addstr (& tmpdir , "/git-difftool.XXXXXX" );
381
+ if (!mkdtemp (tmpdir .buf )) {
382
+ ret = error ("could not create '%s'" , tmpdir .buf );
383
+ goto finish ;
384
+ }
385
+ strbuf_addf (& ldir , "%s/left/" , tmpdir .buf );
386
+ strbuf_addf (& rdir , "%s/right/" , tmpdir .buf );
368
387
strbuf_addstr (& wtdir , workdir );
369
388
if (!wtdir .len || !is_dir_sep (wtdir .buf [wtdir .len - 1 ]))
370
389
strbuf_addch (& wtdir , '/' );
@@ -535,40 +554,19 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,
535
554
*/
536
555
hashmap_for_each_entry (& submodules , & iter , entry ,
537
556
entry /* member name */ ) {
538
- if (* entry -> left ) {
539
- add_path (& ldir , ldir_len , entry -> path );
540
- ensure_leading_directories (ldir .buf );
541
- write_file (ldir .buf , "%s" , entry -> left );
542
- }
543
- if (* entry -> right ) {
544
- add_path (& rdir , rdir_len , entry -> path );
545
- ensure_leading_directories (rdir .buf );
546
- write_file (rdir .buf , "%s" , entry -> right );
547
- }
557
+ write_standin_files (entry , & ldir , ldir_len , & rdir , rdir_len );
548
558
}
549
559
550
560
/*
551
- * Symbolic links require special treatment.The standard "git diff"
561
+ * Symbolic links require special treatment. The standard "git diff"
552
562
* shows only the link itself, not the contents of the link target.
553
563
* This loop replicates that behavior.
554
564
*/
555
565
hashmap_for_each_entry (& symlinks2 , & iter , entry ,
556
566
entry /* member name */ ) {
557
- if (* entry -> left ) {
558
- add_path (& ldir , ldir_len , entry -> path );
559
- ensure_leading_directories (ldir .buf );
560
- unlink (ldir .buf );
561
- write_file (ldir .buf , "%s" , entry -> left );
562
- }
563
- if (* entry -> right ) {
564
- add_path (& rdir , rdir_len , entry -> path );
565
- ensure_leading_directories (rdir .buf );
566
- unlink (rdir .buf );
567
- write_file (rdir .buf , "%s" , entry -> right );
568
- }
569
- }
570
567
571
- strbuf_release (& buf );
568
+ write_standin_files (entry , & ldir , ldir_len , & rdir , rdir_len );
569
+ }
572
570
573
571
strbuf_setlen (& ldir , ldir_len );
574
572
helper_argv [1 ] = ldir .buf ;
@@ -580,7 +578,7 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,
580
578
flags = 0 ;
581
579
} else
582
580
setenv ("GIT_DIFFTOOL_DIRDIFF" , "true" , 1 );
583
- rc = run_command_v_opt (helper_argv , flags );
581
+ ret = run_command_v_opt (helper_argv , flags );
584
582
585
583
/* TODO: audit for interaction with sparse-index. */
586
584
ensure_full_index (& wtindex );
@@ -614,7 +612,7 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,
614
612
if (!indices_loaded ) {
615
613
struct lock_file lock = LOCK_INIT ;
616
614
strbuf_reset (& buf );
617
- strbuf_addf (& buf , "%s/wtindex" , tmpdir );
615
+ strbuf_addf (& buf , "%s/wtindex" , tmpdir . buf );
618
616
if (hold_lock_file_for_update (& lock , buf .buf , 0 ) < 0 ||
619
617
write_locked_index (& wtindex , & lock , COMMIT_LOCK )) {
620
618
ret = error ("could not write %s" , buf .buf );
@@ -644,11 +642,14 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,
644
642
}
645
643
646
644
if (err ) {
647
- warning (_ ("temporary files exist in '%s'." ), tmpdir );
645
+ warning (_ ("temporary files exist in '%s'." ), tmpdir . buf );
648
646
warning (_ ("you may want to cleanup or recover these." ));
649
- exit (1 );
650
- } else
651
- exit_cleanup (tmpdir , rc );
647
+ ret = 1 ;
648
+ } else {
649
+ remove_dir_recursively (& tmpdir , 0 );
650
+ if (ret )
651
+ warning (_ ("failed: %d" ), ret );
652
+ }
652
653
653
654
finish :
654
655
if (fp )
@@ -660,8 +661,9 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,
660
661
strbuf_release (& rdir );
661
662
strbuf_release (& wtdir );
662
663
strbuf_release (& buf );
664
+ strbuf_release (& tmpdir );
663
665
664
- return ret ;
666
+ return ( ret < 0 ) ? 1 : ret ;
665
667
}
666
668
667
669
static int run_file_diff (int prompt , const char * prefix ,
0 commit comments