@@ -808,6 +808,13 @@ static int is_refname_available(const char *refname, const char *oldrefname,
808
808
809
809
struct packed_ref_cache {
810
810
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 ;
811
818
};
812
819
813
820
/*
@@ -826,9 +833,14 @@ static struct ref_cache {
826
833
char name [1 ];
827
834
} ref_cache , * submodule_ref_caches ;
828
835
836
+ /* Lock used for the main packed-refs file: */
837
+ static struct lock_file packlock ;
838
+
829
839
static void clear_packed_ref_cache (struct ref_cache * refs )
830
840
{
831
841
if (refs -> packed ) {
842
+ if (refs -> packed -> lock )
843
+ die ("internal error: packed-ref cache cleared while locked" );
832
844
free_ref_entry (refs -> packed -> root );
833
845
free (refs -> packed );
834
846
refs -> packed = NULL ;
@@ -1038,7 +1050,12 @@ static struct ref_dir *get_packed_refs(struct ref_cache *refs)
1038
1050
1039
1051
void add_packed_ref (const char * refname , const unsigned char * sha1 )
1040
1052
{
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 ),
1042
1059
create_ref_entry (refname , sha1 , REF_ISPACKED , 1 ));
1043
1060
}
1044
1061
@@ -2035,6 +2052,52 @@ static int write_packed_entry_fn(struct ref_entry *entry, void *cb_data)
2035
2052
return 0 ;
2036
2053
}
2037
2054
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
+
2038
2101
struct ref_to_prune {
2039
2102
struct ref_to_prune * next ;
2040
2103
unsigned char sha1 [20 ];
@@ -2148,28 +2211,22 @@ static void prune_refs(struct ref_to_prune *r)
2148
2211
}
2149
2212
}
2150
2213
2151
- static struct lock_file packlock ;
2152
-
2153
2214
int pack_refs (unsigned int flags )
2154
2215
{
2155
2216
struct pack_refs_cb_data cbdata ;
2156
- int fd ;
2157
2217
2158
2218
memset (& cbdata , 0 , sizeof (cbdata ));
2159
2219
cbdata .flags = flags ;
2160
2220
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 );
2163
2222
cbdata .packed_refs = get_packed_refs (& ref_cache );
2164
2223
2165
2224
do_for_each_entry_in_dir (get_loose_refs (& ref_cache ), 0 ,
2166
2225
pack_if_possible_fn , & cbdata );
2167
2226
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 ())
2172
2228
die_errno ("unable to overwrite old ref-pack file" );
2229
+
2173
2230
prune_refs (cbdata .ref_to_prune );
2174
2231
return 0 ;
2175
2232
}
@@ -2233,20 +2290,17 @@ static int curate_packed_ref_fn(struct ref_entry *entry, void *cb_data)
2233
2290
2234
2291
static int repack_without_ref (const char * refname )
2235
2292
{
2236
- int fd ;
2237
2293
struct ref_dir * packed ;
2238
2294
struct string_list refs_to_delete = STRING_LIST_INIT_DUP ;
2239
2295
struct string_list_item * ref_to_delete ;
2240
2296
2241
2297
if (!get_packed_ref (refname ))
2242
2298
return 0 ; /* refname does not exist in packed refs */
2243
2299
2244
- fd = hold_lock_file_for_update (& packlock , git_path ("packed-refs" ), 0 );
2245
- if (fd < 0 ) {
2300
+ if (lock_packed_refs (0 )) {
2246
2301
unable_to_lock_error (git_path ("packed-refs" ), errno );
2247
2302
return error ("cannot delete '%s' from packed refs" , refname );
2248
2303
}
2249
- clear_packed_ref_cache (& ref_cache );
2250
2304
packed = get_packed_refs (& ref_cache );
2251
2305
2252
2306
/* Remove refname from the cache: */
@@ -2255,7 +2309,7 @@ static int repack_without_ref(const char *refname)
2255
2309
* The packed entry disappeared while we were
2256
2310
* acquiring the lock.
2257
2311
*/
2258
- rollback_lock_file ( & packlock );
2312
+ rollback_packed_refs ( );
2259
2313
return 0 ;
2260
2314
}
2261
2315
@@ -2267,9 +2321,7 @@ static int repack_without_ref(const char *refname)
2267
2321
}
2268
2322
2269
2323
/* 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 ();
2273
2325
}
2274
2326
2275
2327
int delete_ref (const char * refname , const unsigned char * sha1 , int delopt )
0 commit comments