88#include "diff.h"
99#include "revision.h"
1010#include "commit-slab.h"
11+ #include "sigchain.h"
1112
1213static int is_shallow = -1 ;
13- static struct stat shallow_stat ;
14+ static struct stat_validity shallow_stat ;
1415static char * alternate_shallow_file ;
1516
1617void set_alternate_shallow_file (const char * path , int override )
@@ -52,12 +53,12 @@ int is_repository_shallow(void)
5253 * shallow file should be used. We could just open it and it
5354 * will likely fail. But let's do an explicit check instead.
5455 */
55- if (!* path ||
56- stat (path , & shallow_stat ) ||
57- (fp = fopen (path , "r" )) == NULL ) {
56+ if (!* path || (fp = fopen (path , "r" )) == NULL ) {
57+ stat_validity_clear (& shallow_stat );
5858 is_shallow = 0 ;
5959 return is_shallow ;
6060 }
61+ stat_validity_update (& shallow_stat , fileno (fp ));
6162 is_shallow = 1 ;
6263
6364 while (fgets (buf , sizeof (buf ), fp )) {
@@ -137,21 +138,11 @@ struct commit_list *get_shallow_commits(struct object_array *heads, int depth,
137138
138139void check_shallow_file_for_update (void )
139140{
140- struct stat st ;
141-
142- if (!is_shallow )
143- return ;
144- else if (is_shallow == -1 )
141+ if (is_shallow == -1 )
145142 die ("BUG: shallow must be initialized by now" );
146143
147- if (stat (git_path ("shallow" ), & st ))
148- die ("shallow file was removed during fetch" );
149- else if (st .st_mtime != shallow_stat .st_mtime
150- #ifdef USE_NSEC
151- || ST_MTIME_NSEC (st ) != ST_MTIME_NSEC (shallow_stat )
152- #endif
153- )
154- die ("shallow file was changed during fetch" );
144+ if (!stat_validity_check (& shallow_stat , git_path ("shallow" )))
145+ die ("shallow file has changed since we read it" );
155146}
156147
157148#define SEEN_ONLY 1
@@ -216,27 +207,53 @@ int write_shallow_commits(struct strbuf *out, int use_pack_protocol,
216207 return write_shallow_commits_1 (out , use_pack_protocol , extra , 0 );
217208}
218209
219- char * setup_temporary_shallow (const struct sha1_array * extra )
210+ static struct strbuf temporary_shallow = STRBUF_INIT ;
211+
212+ static void remove_temporary_shallow (void )
213+ {
214+ if (temporary_shallow .len ) {
215+ unlink_or_warn (temporary_shallow .buf );
216+ strbuf_reset (& temporary_shallow );
217+ }
218+ }
219+
220+ static void remove_temporary_shallow_on_signal (int signo )
221+ {
222+ remove_temporary_shallow ();
223+ sigchain_pop (signo );
224+ raise (signo );
225+ }
226+
227+ const char * setup_temporary_shallow (const struct sha1_array * extra )
220228{
229+ static int installed_handler ;
221230 struct strbuf sb = STRBUF_INIT ;
222231 int fd ;
223232
233+ if (temporary_shallow .len )
234+ die ("BUG: attempt to create two temporary shallow files" );
235+
224236 if (write_shallow_commits (& sb , 0 , extra )) {
225- struct strbuf path = STRBUF_INIT ;
226- strbuf_addstr (& path , git_path ("shallow_XXXXXX" ));
227- fd = xmkstemp (path .buf );
237+ strbuf_addstr (& temporary_shallow , git_path ("shallow_XXXXXX" ));
238+ fd = xmkstemp (temporary_shallow .buf );
239+
240+ if (!installed_handler ) {
241+ atexit (remove_temporary_shallow );
242+ sigchain_push_common (remove_temporary_shallow_on_signal );
243+ }
244+
228245 if (write_in_full (fd , sb .buf , sb .len ) != sb .len )
229246 die_errno ("failed to write to %s" ,
230- path .buf );
247+ temporary_shallow .buf );
231248 close (fd );
232249 strbuf_release (& sb );
233- return strbuf_detach ( & path , NULL ) ;
250+ return temporary_shallow . buf ;
234251 }
235252 /*
236253 * is_repository_shallow() sees empty string as "no shallow
237254 * file".
238255 */
239- return xstrdup ( "" ) ;
256+ return temporary_shallow . buf ;
240257}
241258
242259void setup_alternate_shallow (struct lock_file * shallow_lock ,
@@ -246,9 +263,9 @@ void setup_alternate_shallow(struct lock_file *shallow_lock,
246263 struct strbuf sb = STRBUF_INIT ;
247264 int fd ;
248265
249- check_shallow_file_for_update ();
250266 fd = hold_lock_file_for_update (shallow_lock , git_path ("shallow" ),
251267 LOCK_DIE_ON_ERROR );
268+ check_shallow_file_for_update ();
252269 if (write_shallow_commits (& sb , 0 , extra )) {
253270 if (write_in_full (fd , sb .buf , sb .len ) != sb .len )
254271 die_errno ("failed to write to %s" ,
@@ -293,9 +310,9 @@ void prune_shallow(int show_only)
293310 strbuf_release (& sb );
294311 return ;
295312 }
296- check_shallow_file_for_update ();
297313 fd = hold_lock_file_for_update (& shallow_lock , git_path ("shallow" ),
298314 LOCK_DIE_ON_ERROR );
315+ check_shallow_file_for_update ();
299316 if (write_shallow_commits_1 (& sb , 0 , NULL , SEEN_ONLY )) {
300317 if (write_in_full (fd , sb .buf , sb .len ) != sb .len )
301318 die_errno ("failed to write to %s" ,
0 commit comments