@@ -352,18 +352,20 @@ static int push_tip_to_list(const char *refname, const unsigned char *sha1, int
352352static int expire_reflog (const char * refname , const unsigned char * sha1 ,
353353 struct cmd_reflog_expire_cb * cmd )
354354{
355+ static struct lock_file reflog_lock ;
355356 struct expire_reflog_cb cb ;
356357 struct ref_lock * lock ;
357- char * log_file , * newlog_path = NULL ;
358+ char * log_file ;
358359 struct commit * tip_commit ;
359360 struct commit_list * tips ;
360361 int status = 0 ;
361362
362363 memset (& cb , 0 , sizeof (cb ));
363364
364365 /*
365- * we take the lock for the ref itself to prevent it from
366- * getting updated.
366+ * The reflog file is locked by holding the lock on the
367+ * reference itself, plus we might need to update the
368+ * reference if --updateref was specified:
367369 */
368370 lock = lock_any_ref_for_update (refname , sha1 , 0 , NULL );
369371 if (!lock )
@@ -372,10 +374,29 @@ static int expire_reflog(const char *refname, const unsigned char *sha1,
372374 unlock_ref (lock );
373375 return 0 ;
374376 }
377+
375378 log_file = git_pathdup ("logs/%s" , refname );
376379 if (!cmd -> dry_run ) {
377- newlog_path = git_pathdup ("logs/%s.lock" , refname );
378- cb .newlog = fopen (newlog_path , "w" );
380+ /*
381+ * Even though holding $GIT_DIR/logs/$reflog.lock has
382+ * no locking implications, we use the lock_file
383+ * machinery here anyway because it does a lot of the
384+ * work we need, including cleaning up if the program
385+ * exits unexpectedly.
386+ */
387+ if (hold_lock_file_for_update (& reflog_lock , log_file , 0 ) < 0 ) {
388+ struct strbuf err = STRBUF_INIT ;
389+ unable_to_lock_message (log_file , errno , & err );
390+ error ("%s" , err .buf );
391+ strbuf_release (& err );
392+ goto failure ;
393+ }
394+ cb .newlog = fdopen_lock_file (& reflog_lock , "w" );
395+ if (!cb .newlog ) {
396+ error ("cannot fdopen %s (%s)" ,
397+ reflog_lock .filename .buf , strerror (errno ));
398+ goto failure ;
399+ }
379400 }
380401
381402 cb .cmd = cmd ;
@@ -423,32 +444,33 @@ static int expire_reflog(const char *refname, const unsigned char *sha1,
423444 }
424445
425446 if (cb .newlog ) {
426- if (fclose (cb .newlog )) {
427- status |= error ("%s: %s" , strerror (errno ),
428- newlog_path );
429- unlink (newlog_path );
447+ if (close_lock_file (& reflog_lock )) {
448+ status |= error ("couldn't write %s: %s" , log_file ,
449+ strerror (errno ));
430450 } else if (cmd -> updateref &&
431451 (write_in_full (lock -> lock_fd ,
432452 sha1_to_hex (cb .last_kept_sha1 ), 40 ) != 40 ||
433453 write_str_in_full (lock -> lock_fd , "\n" ) != 1 ||
434454 close_ref (lock ) < 0 )) {
435- status |= error ("Couldn 't write %s" ,
455+ status |= error ("couldn 't write %s" ,
436456 lock -> lk -> filename .buf );
437- unlink (newlog_path );
438- } else if (rename (newlog_path , log_file )) {
439- status |= error ("cannot rename %s to %s" ,
440- newlog_path , log_file );
441- unlink (newlog_path );
457+ rollback_lock_file (& reflog_lock );
458+ } else if (commit_lock_file (& reflog_lock )) {
459+ status |= error ("unable to commit reflog '%s' (%s)" ,
460+ log_file , strerror (errno ));
442461 } else if (cmd -> updateref && commit_ref (lock )) {
443- status |= error ("Couldn't set %s" , lock -> ref_name );
444- } else {
445- adjust_shared_perm (log_file );
462+ status |= error ("couldn't set %s" , lock -> ref_name );
446463 }
447464 }
448- free (newlog_path );
449465 free (log_file );
450466 unlock_ref (lock );
451467 return status ;
468+
469+ failure :
470+ rollback_lock_file (& reflog_lock );
471+ free (log_file );
472+ unlock_ref (lock );
473+ return -1 ;
452474}
453475
454476static int collect_reflog (const char * ref , const unsigned char * sha1 , int unused , void * cb_data )
0 commit comments