1212#include "run-command.h"
1313#include "utf8.h"
1414#include "userdiff.h"
15+ #include "sigchain.h"
1516
1617#ifdef NO_FAST_WORKING_DIRECTORY
1718#define FAST_WORKING_DIRECTORY 0
@@ -170,6 +171,33 @@ static struct diff_tempfile {
170171 char tmp_path [PATH_MAX ];
171172} diff_temp [2 ];
172173
174+ static struct diff_tempfile * claim_diff_tempfile (void ) {
175+ int i ;
176+ for (i = 0 ; i < ARRAY_SIZE (diff_temp ); i ++ )
177+ if (!diff_temp [i ].name )
178+ return diff_temp + i ;
179+ die ("BUG: diff is failing to clean up its tempfiles" );
180+ }
181+
182+ static int remove_tempfile_installed ;
183+
184+ static void remove_tempfile (void )
185+ {
186+ int i ;
187+ for (i = 0 ; i < ARRAY_SIZE (diff_temp ); i ++ )
188+ if (diff_temp [i ].name == diff_temp [i ].tmp_path ) {
189+ unlink (diff_temp [i ].name );
190+ diff_temp [i ].name = NULL ;
191+ }
192+ }
193+
194+ static void remove_tempfile_on_signal (int signo )
195+ {
196+ remove_tempfile ();
197+ sigchain_pop (signo );
198+ raise (signo );
199+ }
200+
173201static int count_lines (const char * data , int size )
174202{
175203 int count , ch , completely_empty = 1 , nl_just_seen = 0 ;
@@ -1940,10 +1968,11 @@ static void prep_temp_blob(struct diff_tempfile *temp,
19401968 sprintf (temp -> mode , "%06o" , mode );
19411969}
19421970
1943- static void prepare_temp_file (const char * name ,
1944- struct diff_tempfile * temp ,
1945- struct diff_filespec * one )
1971+ static struct diff_tempfile * prepare_temp_file (const char * name ,
1972+ struct diff_filespec * one )
19461973{
1974+ struct diff_tempfile * temp = claim_diff_tempfile ();
1975+
19471976 if (!DIFF_FILE_VALID (one )) {
19481977 not_a_valid_file :
19491978 /* A '-' entry produces this for file-2, and
@@ -1952,7 +1981,13 @@ static void prepare_temp_file(const char *name,
19521981 temp -> name = "/dev/null" ;
19531982 strcpy (temp -> hex , "." );
19541983 strcpy (temp -> mode , "." );
1955- return ;
1984+ return temp ;
1985+ }
1986+
1987+ if (!remove_tempfile_installed ) {
1988+ atexit (remove_tempfile );
1989+ sigchain_push_common (remove_tempfile_on_signal );
1990+ remove_tempfile_installed = 1 ;
19561991 }
19571992
19581993 if (!one -> sha1_valid ||
@@ -1992,32 +2027,15 @@ static void prepare_temp_file(const char *name,
19922027 */
19932028 sprintf (temp -> mode , "%06o" , one -> mode );
19942029 }
1995- return ;
2030+ return temp ;
19962031 }
19972032 else {
19982033 if (diff_populate_filespec (one , 0 ))
19992034 die ("cannot read data blob for %s" , one -> path );
20002035 prep_temp_blob (temp , one -> data , one -> size ,
20012036 one -> sha1 , one -> mode );
20022037 }
2003- }
2004-
2005- static void remove_tempfile (void )
2006- {
2007- int i ;
2008-
2009- for (i = 0 ; i < 2 ; i ++ )
2010- if (diff_temp [i ].name == diff_temp [i ].tmp_path ) {
2011- unlink (diff_temp [i ].name );
2012- diff_temp [i ].name = NULL ;
2013- }
2014- }
2015-
2016- static void remove_tempfile_on_signal (int signo )
2017- {
2018- remove_tempfile ();
2019- signal (SIGINT , SIG_DFL );
2020- raise (signo );
2038+ return temp ;
20212039}
20222040
20232041/* An external diff command takes:
@@ -2035,34 +2053,22 @@ static void run_external_diff(const char *pgm,
20352053 int complete_rewrite )
20362054{
20372055 const char * spawn_arg [10 ];
2038- struct diff_tempfile * temp = diff_temp ;
20392056 int retval ;
2040- static int atexit_asked = 0 ;
2041- const char * othername ;
20422057 const char * * arg = & spawn_arg [0 ];
20432058
2044- othername = (other ? other : name );
2045- if (one && two ) {
2046- prepare_temp_file (name , & temp [0 ], one );
2047- prepare_temp_file (othername , & temp [1 ], two );
2048- if (! atexit_asked &&
2049- (temp [0 ].name == temp [0 ].tmp_path ||
2050- temp [1 ].name == temp [1 ].tmp_path )) {
2051- atexit_asked = 1 ;
2052- atexit (remove_tempfile );
2053- }
2054- signal (SIGINT , remove_tempfile_on_signal );
2055- }
2056-
20572059 if (one && two ) {
2060+ struct diff_tempfile * temp_one , * temp_two ;
2061+ const char * othername = (other ? other : name );
2062+ temp_one = prepare_temp_file (name , one );
2063+ temp_two = prepare_temp_file (othername , two );
20582064 * arg ++ = pgm ;
20592065 * arg ++ = name ;
2060- * arg ++ = temp [ 0 ]. name ;
2061- * arg ++ = temp [ 0 ]. hex ;
2062- * arg ++ = temp [ 0 ]. mode ;
2063- * arg ++ = temp [ 1 ]. name ;
2064- * arg ++ = temp [ 1 ]. hex ;
2065- * arg ++ = temp [ 1 ]. mode ;
2066+ * arg ++ = temp_one -> name ;
2067+ * arg ++ = temp_one -> hex ;
2068+ * arg ++ = temp_one -> mode ;
2069+ * arg ++ = temp_two -> name ;
2070+ * arg ++ = temp_two -> hex ;
2071+ * arg ++ = temp_two -> mode ;
20662072 if (other ) {
20672073 * arg ++ = other ;
20682074 * arg ++ = xfrm_msg ;
@@ -3537,15 +3543,15 @@ void diff_unmerge(struct diff_options *options,
35373543static char * run_textconv (const char * pgm , struct diff_filespec * spec ,
35383544 size_t * outsize )
35393545{
3540- struct diff_tempfile temp ;
3546+ struct diff_tempfile * temp ;
35413547 const char * argv [3 ];
35423548 const char * * arg = argv ;
35433549 struct child_process child ;
35443550 struct strbuf buf = STRBUF_INIT ;
35453551
3546- prepare_temp_file (spec -> path , & temp , spec );
3552+ temp = prepare_temp_file (spec -> path , spec );
35473553 * arg ++ = pgm ;
3548- * arg ++ = temp . name ;
3554+ * arg ++ = temp -> name ;
35493555 * arg = NULL ;
35503556
35513557 memset (& child , 0 , sizeof (child ));
@@ -3554,13 +3560,11 @@ static char *run_textconv(const char *pgm, struct diff_filespec *spec,
35543560 if (start_command (& child ) != 0 ||
35553561 strbuf_read (& buf , child .out , 0 ) < 0 ||
35563562 finish_command (& child ) != 0 ) {
3557- if (temp .name == temp .tmp_path )
3558- unlink (temp .name );
3563+ remove_tempfile ();
35593564 error ("error running textconv command '%s'" , pgm );
35603565 return NULL ;
35613566 }
3562- if (temp .name == temp .tmp_path )
3563- unlink (temp .name );
3567+ remove_tempfile ();
35643568
35653569 return strbuf_detach (& buf , outsize );
35663570}
0 commit comments