repack_without_ref(): reimplement using do_for_each_ref_in_array()

It costs a bit of boilerplate, but it means that the function can be ignorant of how cached refs are stored. Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Michael Haggerty committed Apr 10, 2012 at 07:30 UTC d66da478f26df3114af1177fa5614035439178ed
1 file changed +61 -33
refs.c
+61 -33
@@ -333,6 +333,30 @@ static int do_for_each_ref_in_arrays(struct ref_array *array1,
333 return 0;
334 }
335
336 +/*
337 + * Return true iff refname1 and refname2 conflict with each other.
338 + * Two reference names conflict if one of them exactly matches the
339 + * leading components of the other; e.g., "foo/bar" conflicts with
340 + * both "foo" and with "foo/bar/baz" but not with "foo/bar" or
341 + * "foo/barbados".
342 + */
343 +static int names_conflict(const char *refname1, const char *refname2)
344 +{
345 + int len1 = strlen(refname1);
346 + int len2 = strlen(refname2);
347 + int cmplen;
348 + const char *lead;
349 +
350 + if (len1 < len2) {
351 + cmplen = len1;
352 + lead = refname2;
353 + } else {
354 + cmplen = len2;
355 + lead = refname1;
356 + }
357 + return !strncmp(refname1, refname2, cmplen) && lead[cmplen] == '/';
358 +}
359 +
360 /*
361 * Return true iff a reference named refname could be created without
362 * conflicting with the name of an existing reference. If oldrefname
@@ -343,20 +367,15 @@ static int do_for_each_ref_in_arrays(struct ref_array *array1,
367 static int is_refname_available(const char *refname, const char *oldrefname,
368 struct ref_array *array)
369 {
346 - int i, namlen = strlen(refname); /* e.g. 'foo/bar' */
370 + int i;
371 for (i = 0; i < array->nr; i++) {
372 struct ref_entry *entry = array->refs[i];
349 - /* entry->name could be 'foo' or 'foo/bar/baz' */
350 - if (!oldrefname || strcmp(oldrefname, entry->name)) {
351 - int len = strlen(entry->name);
352 - int cmplen = (namlen < len) ? namlen : len;
353 - const char *lead = (namlen < len) ? entry->name : refname;
354 - if (!strncmp(refname, entry->name, cmplen) &&
355 - lead[cmplen] == '/') {
356 - error("'%s' exists; cannot create '%s'",
357 - entry->name, refname);
358 - return 0;
359 - }
373 + if (oldrefname && !strcmp(oldrefname, entry->name))
374 + continue;
375 + if (names_conflict(refname, entry->name)) {
376 + error("'%s' exists; cannot create '%s'",
377 + entry->name, refname);
378 + return 0;
379 }
380 }
381 return 1;
@@ -1333,36 +1352,45 @@ struct ref_lock *lock_any_ref_for_update(const char *refname,
1352 return lock_ref_sha1_basic(refname, old_sha1, flags, NULL);
1353 }
1354
1355 +struct repack_without_ref_sb {
1356 + const char *refname;
1357 + int fd;
1358 +};
1359 +
1360 +static int repack_without_ref_fn(const char *refname, const unsigned char *sha1,
1361 + int flags, void *cb_data)
1362 +{
1363 + struct repack_without_ref_sb *data = cb_data;
1364 + char line[PATH_MAX + 100];
1365 + int len;
1366 +
1367 + if (!strcmp(data->refname, refname))
1368 + return 0;
1369 + len = snprintf(line, sizeof(line), "%s %s\n",
1370 + sha1_to_hex(sha1), refname);
1371 + /* this should not happen but just being defensive */
1372 + if (len > sizeof(line))
1373 + die("too long a refname '%s'", refname);
1374 + write_or_die(data->fd, line, len);
1375 + return 0;
1376 +}
1377 +
1378 static struct lock_file packlock;
1379
1380 static int repack_without_ref(const char *refname)
1381 {
1340 - struct ref_array *packed;
1341 - int fd, i;
1342 -
1343 - packed = get_packed_refs(get_ref_cache(NULL));
1382 + struct repack_without_ref_sb data;
1383 + struct ref_array *packed = get_packed_refs(get_ref_cache(NULL));
1384 + sort_ref_array(packed);
1385 if (search_ref_array(packed, refname) == NULL)
1386 return 0;
1346 - fd = hold_lock_file_for_update(&packlock, git_path("packed-refs"), 0);
1347 - if (fd < 0) {
1387 + data.refname = refname;
1388 + data.fd = hold_lock_file_for_update(&packlock, git_path("packed-refs"), 0);
1389 + if (data.fd < 0) {
1390 unable_to_lock_error(git_path("packed-refs"), errno);
1391 return error("cannot delete '%s' from packed refs", refname);
1392 }
1351 -
1352 - for (i = 0; i < packed->nr; i++) {
1353 - char line[PATH_MAX + 100];
1354 - int len;
1355 - struct ref_entry *ref = packed->refs[i];
1356 -
1357 - if (!strcmp(refname, ref->name))
1358 - continue;
1359 - len = snprintf(line, sizeof(line), "%s %s\n",
1360 - sha1_to_hex(ref->sha1), ref->name);
1361 - /* this should not happen but just being defensive */
1362 - if (len > sizeof(line))
1363 - die("too long a refname '%s'", ref->name);
1364 - write_or_die(fd, line, len);
1365 - }
1393 + do_for_each_ref_in_array(packed, 0, "", repack_without_ref_fn, 0, 0, &data);
1394 return commit_lock_file(&packlock);
1395 }
1396