@@ -808,6 +808,13 @@ static int is_refname_available(const char *refname, const char *oldrefname,
808808
809809struct packed_ref_cache {
810810 struct ref_entry * root ;
811+
812+ /*
813+ * Iff the packed-refs file associated with this instance is
814+ * currently locked for writing, this points at the associated
815+ * lock (which is owned by somebody else).
816+ */
817+ struct lock_file * lock ;
811818};
812819
813820/*
@@ -826,9 +833,14 @@ static struct ref_cache {
826833 char name [1 ];
827834} ref_cache , * submodule_ref_caches ;
828835
836+ /* Lock used for the main packed-refs file: */
837+ static struct lock_file packlock ;
838+
829839static void clear_packed_ref_cache (struct ref_cache * refs )
830840{
831841 if (refs -> packed ) {
842+ if (refs -> packed -> lock )
843+ die ("internal error: packed-ref cache cleared while locked" );
832844 free_ref_entry (refs -> packed -> root );
833845 free (refs -> packed );
834846 refs -> packed = NULL ;
@@ -1038,7 +1050,12 @@ static struct ref_dir *get_packed_refs(struct ref_cache *refs)
10381050
10391051void add_packed_ref (const char * refname , const unsigned char * sha1 )
10401052{
1041- add_ref (get_packed_refs (& ref_cache ),
1053+ struct packed_ref_cache * packed_ref_cache =
1054+ get_packed_ref_cache (& ref_cache );
1055+
1056+ if (!packed_ref_cache -> lock )
1057+ die ("internal error: packed refs not locked" );
1058+ add_ref (get_packed_ref_dir (packed_ref_cache ),
10421059 create_ref_entry (refname , sha1 , REF_ISPACKED , 1 ));
10431060}
10441061
@@ -2035,6 +2052,52 @@ static int write_packed_entry_fn(struct ref_entry *entry, void *cb_data)
20352052 return 0 ;
20362053}
20372054
2055+ int lock_packed_refs (int flags )
2056+ {
2057+ struct packed_ref_cache * packed_ref_cache ;
2058+
2059+ /* Discard the old cache because it might be invalid: */
2060+ clear_packed_ref_cache (& ref_cache );
2061+ if (hold_lock_file_for_update (& packlock , git_path ("packed-refs" ), flags ) < 0 )
2062+ return -1 ;
2063+ /* Read the current packed-refs while holding the lock: */
2064+ packed_ref_cache = get_packed_ref_cache (& ref_cache );
2065+ packed_ref_cache -> lock = & packlock ;
2066+ return 0 ;
2067+ }
2068+
2069+ int commit_packed_refs (void )
2070+ {
2071+ struct packed_ref_cache * packed_ref_cache =
2072+ get_packed_ref_cache (& ref_cache );
2073+ int error = 0 ;
2074+
2075+ if (!packed_ref_cache -> lock )
2076+ die ("internal error: packed-refs not locked" );
2077+ write_or_die (packed_ref_cache -> lock -> fd ,
2078+ PACKED_REFS_HEADER , strlen (PACKED_REFS_HEADER ));
2079+
2080+ do_for_each_entry_in_dir (get_packed_ref_dir (packed_ref_cache ),
2081+ 0 , write_packed_entry_fn ,
2082+ & packed_ref_cache -> lock -> fd );
2083+ if (commit_lock_file (packed_ref_cache -> lock ))
2084+ error = -1 ;
2085+ packed_ref_cache -> lock = NULL ;
2086+ return error ;
2087+ }
2088+
2089+ void rollback_packed_refs (void )
2090+ {
2091+ struct packed_ref_cache * packed_ref_cache =
2092+ get_packed_ref_cache (& ref_cache );
2093+
2094+ if (!packed_ref_cache -> lock )
2095+ die ("internal error: packed-refs not locked" );
2096+ rollback_lock_file (packed_ref_cache -> lock );
2097+ packed_ref_cache -> lock = NULL ;
2098+ clear_packed_ref_cache (& ref_cache );
2099+ }
2100+
20382101struct ref_to_prune {
20392102 struct ref_to_prune * next ;
20402103 unsigned char sha1 [20 ];
@@ -2148,28 +2211,22 @@ static void prune_refs(struct ref_to_prune *r)
21482211 }
21492212}
21502213
2151- static struct lock_file packlock ;
2152-
21532214int pack_refs (unsigned int flags )
21542215{
21552216 struct pack_refs_cb_data cbdata ;
2156- int fd ;
21572217
21582218 memset (& cbdata , 0 , sizeof (cbdata ));
21592219 cbdata .flags = flags ;
21602220
2161- fd = hold_lock_file_for_update (& packlock , git_path ("packed-refs" ),
2162- LOCK_DIE_ON_ERROR );
2221+ lock_packed_refs (LOCK_DIE_ON_ERROR );
21632222 cbdata .packed_refs = get_packed_refs (& ref_cache );
21642223
21652224 do_for_each_entry_in_dir (get_loose_refs (& ref_cache ), 0 ,
21662225 pack_if_possible_fn , & cbdata );
21672226
2168- write_or_die (fd , PACKED_REFS_HEADER , strlen (PACKED_REFS_HEADER ));
2169- do_for_each_entry_in_dir (cbdata .packed_refs , 0 , write_packed_entry_fn , & fd );
2170-
2171- if (commit_lock_file (& packlock ) < 0 )
2227+ if (commit_packed_refs ())
21722228 die_errno ("unable to overwrite old ref-pack file" );
2229+
21732230 prune_refs (cbdata .ref_to_prune );
21742231 return 0 ;
21752232}
@@ -2233,20 +2290,17 @@ static int curate_packed_ref_fn(struct ref_entry *entry, void *cb_data)
22332290
22342291static int repack_without_ref (const char * refname )
22352292{
2236- int fd ;
22372293 struct ref_dir * packed ;
22382294 struct string_list refs_to_delete = STRING_LIST_INIT_DUP ;
22392295 struct string_list_item * ref_to_delete ;
22402296
22412297 if (!get_packed_ref (refname ))
22422298 return 0 ; /* refname does not exist in packed refs */
22432299
2244- fd = hold_lock_file_for_update (& packlock , git_path ("packed-refs" ), 0 );
2245- if (fd < 0 ) {
2300+ if (lock_packed_refs (0 )) {
22462301 unable_to_lock_error (git_path ("packed-refs" ), errno );
22472302 return error ("cannot delete '%s' from packed refs" , refname );
22482303 }
2249- clear_packed_ref_cache (& ref_cache );
22502304 packed = get_packed_refs (& ref_cache );
22512305
22522306 /* Remove refname from the cache: */
@@ -2255,7 +2309,7 @@ static int repack_without_ref(const char *refname)
22552309 * The packed entry disappeared while we were
22562310 * acquiring the lock.
22572311 */
2258- rollback_lock_file ( & packlock );
2312+ rollback_packed_refs ( );
22592313 return 0 ;
22602314 }
22612315
@@ -2267,9 +2321,7 @@ static int repack_without_ref(const char *refname)
22672321 }
22682322
22692323 /* Write what remains: */
2270- write_or_die (fd , PACKED_REFS_HEADER , strlen (PACKED_REFS_HEADER ));
2271- do_for_each_entry_in_dir (packed , 0 , write_packed_entry_fn , & fd );
2272- return commit_lock_file (& packlock );
2324+ return commit_packed_refs ();
22732325}
22742326
22752327int delete_ref (const char * refname , const unsigned char * sha1 , int delopt )
0 commit comments