@@ -467,6 +467,57 @@ static struct ref_entry *find_ref(struct ref_dir *dir, const char *refname)
467
467
return (entry -> flag & REF_DIR ) ? NULL : entry ;
468
468
}
469
469
470
+ /*
471
+ * Remove the entry with the given name from dir, recursing into
472
+ * subdirectories as necessary. If refname is the name of a directory
473
+ * (i.e., ends with '/'), then remove the directory and its contents.
474
+ * If the removal was successful, return the number of entries
475
+ * remaining in the directory entry that contained the deleted entry.
476
+ * If the name was not found, return -1. Please note that this
477
+ * function only deletes the entry from the cache; it does not delete
478
+ * it from the filesystem or ensure that other cache entries (which
479
+ * might be symbolic references to the removed entry) are updated.
480
+ * Nor does it remove any containing dir entries that might be made
481
+ * empty by the removal. dir must represent the top-level directory
482
+ * and must already be complete.
483
+ */
484
+ static int remove_entry (struct ref_dir * dir , const char * refname )
485
+ {
486
+ int refname_len = strlen (refname );
487
+ int entry_index ;
488
+ struct ref_entry * entry ;
489
+ int is_dir = refname [refname_len - 1 ] == '/' ;
490
+ if (is_dir ) {
491
+ /*
492
+ * refname represents a reference directory. Remove
493
+ * the trailing slash; otherwise we will get the
494
+ * directory *representing* refname rather than the
495
+ * one *containing* it.
496
+ */
497
+ char * dirname = xmemdupz (refname , refname_len - 1 );
498
+ dir = find_containing_dir (dir , dirname , 0 );
499
+ free (dirname );
500
+ } else {
501
+ dir = find_containing_dir (dir , refname , 0 );
502
+ }
503
+ if (!dir )
504
+ return -1 ;
505
+ entry_index = search_ref_dir (dir , refname , refname_len );
506
+ if (entry_index == -1 )
507
+ return -1 ;
508
+ entry = dir -> entries [entry_index ];
509
+
510
+ memmove (& dir -> entries [entry_index ],
511
+ & dir -> entries [entry_index + 1 ],
512
+ (dir -> nr - entry_index - 1 ) * sizeof (* dir -> entries )
513
+ );
514
+ dir -> nr -- ;
515
+ if (dir -> sorted > entry_index )
516
+ dir -> sorted -- ;
517
+ free_ref_entry (entry );
518
+ return dir -> nr ;
519
+ }
520
+
470
521
/*
471
522
* Add a ref_entry to the ref_dir (unsorted), recursing into
472
523
* subdirectories as necessary. dir must represent the top-level
@@ -1895,19 +1946,12 @@ struct ref_lock *lock_any_ref_for_update(const char *refname,
1895
1946
return lock_ref_sha1_basic (refname , old_sha1 , flags , NULL );
1896
1947
}
1897
1948
1898
- struct repack_without_ref_sb {
1899
- const char * refname ;
1900
- int fd ;
1901
- };
1902
-
1903
- static int repack_without_ref_fn (struct ref_entry * entry , void * cb_data )
1949
+ static int repack_ref_fn (struct ref_entry * entry , void * cb_data )
1904
1950
{
1905
- struct repack_without_ref_sb * data = cb_data ;
1951
+ int * fd = cb_data ;
1906
1952
char line [PATH_MAX + 100 ];
1907
1953
int len ;
1908
1954
1909
- if (!strcmp (data -> refname , entry -> name ))
1910
- return 0 ;
1911
1955
if (entry -> flag & REF_ISBROKEN ) {
1912
1956
/* This shouldn't happen to packed refs. */
1913
1957
error ("%s is broken!" , entry -> name );
@@ -1948,30 +1992,38 @@ static int repack_without_ref_fn(struct ref_entry *entry, void *cb_data)
1948
1992
/* this should not happen but just being defensive */
1949
1993
if (len > sizeof (line ))
1950
1994
die ("too long a refname '%s'" , entry -> name );
1951
- write_or_die (data -> fd , line , len );
1995
+ write_or_die (* fd , line , len );
1952
1996
return 0 ;
1953
1997
}
1954
1998
1955
1999
static struct lock_file packlock ;
1956
2000
1957
2001
static int repack_without_ref (const char * refname )
1958
2002
{
1959
- struct repack_without_ref_sb data ;
2003
+ int fd ;
1960
2004
struct ref_cache * refs = get_ref_cache (NULL );
1961
2005
struct ref_dir * packed ;
1962
2006
1963
2007
if (!get_packed_ref (refname ))
1964
2008
return 0 ; /* refname does not exist in packed refs */
1965
2009
1966
- data .refname = refname ;
1967
- data .fd = hold_lock_file_for_update (& packlock , git_path ("packed-refs" ), 0 );
1968
- if (data .fd < 0 ) {
2010
+ fd = hold_lock_file_for_update (& packlock , git_path ("packed-refs" ), 0 );
2011
+ if (fd < 0 ) {
1969
2012
unable_to_lock_error (git_path ("packed-refs" ), errno );
1970
2013
return error ("cannot delete '%s' from packed refs" , refname );
1971
2014
}
1972
2015
clear_packed_ref_cache (refs );
1973
2016
packed = get_packed_refs (refs );
1974
- do_for_each_entry_in_dir (packed , 0 , repack_without_ref_fn , & data );
2017
+ /* Remove refname from the cache. */
2018
+ if (remove_entry (packed , refname ) == -1 ) {
2019
+ /*
2020
+ * The packed entry disappeared while we were
2021
+ * acquiring the lock.
2022
+ */
2023
+ rollback_lock_file (& packlock );
2024
+ return 0 ;
2025
+ }
2026
+ do_for_each_entry_in_dir (packed , 0 , repack_ref_fn , & fd );
1975
2027
return commit_lock_file (& packlock );
1976
2028
}
1977
2029
@@ -2000,7 +2052,7 @@ int delete_ref(const char *refname, const unsigned char *sha1, int delopt)
2000
2052
ret |= repack_without_ref (lock -> ref_name );
2001
2053
2002
2054
unlink_or_warn (git_path ("logs/%s" , lock -> ref_name ));
2003
- invalidate_ref_cache ( NULL );
2055
+ clear_loose_ref_cache ( get_ref_cache ( NULL ) );
2004
2056
unlock_ref (lock );
2005
2057
return ret ;
2006
2058
}
0 commit comments