packfile: factor out --pack_header argument parsing

Both index-pack and unpack-objects accept a --pack_header argument. This is an undocumented internal argument used by receive-pack and fetch to pass along information about the header of the pack, which they've already read from the incoming stream. In preparation for a bugfix, let's factor the duplicated code into a common helper. The callers are still responsible for identifying the option. While this could likewise be factored out, it is more flexible this way (e.g., if they ever started using parse-options and wanted to handle both the stuck and unstuck forms). Likewise, the callers are responsible for reporting errors, though they both just call die(). I've tweaked unpack-objects to match index-pack in marking the error for translation. Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Jeff King committed Jan 19, 2025 at 08:23 UTC 798e0f451661f81f4568dce4033cf1c9076f224f
4 files changed +30 -23
builtin/index-pack.c
+3 -11
@@ -1801,18 +1801,10 @@ int cmd_index_pack(int argc, const char **argv, const char *prefix)
1801 nr_threads = 1;
1802 }
1803 } else if (starts_with(arg, "--pack_header=")) {
1804 - struct pack_header *hdr;
1805 - char *c;
1806 -
1807 - hdr = (struct pack_header *)input_buffer;
1808 - hdr->hdr_signature = htonl(PACK_SIGNATURE);
1809 - hdr->hdr_version = htonl(strtoul(arg + 14, &c, 10));
1810 - if (*c != ',')
1811 - die(_("bad %s"), arg);
1812 - hdr->hdr_entries = htonl(strtoul(c + 1, &c, 10));
1813 - if (*c)
1804 + if (parse_pack_header_option(arg + 14,
1805 + input_buffer,
1806 + &input_len) < 0)
1807 die(_("bad %s"), arg);
1815 - input_len = sizeof(*hdr);
1808 } else if (!strcmp(arg, "-v")) {
1809 verbose = 1;
1810 } else if (!strcmp(arg, "--progress-title")) {
builtin/unpack-objects.c
+4 -12
@@ -15,6 +15,7 @@
15 #include "progress.h"
16 #include "decorate.h"
17 #include "fsck.h"
18 +#include "packfile.h"
19
20 static int dry_run, quiet, recover, has_errors, strict;
21 static const char unpack_usage[] = "git unpack-objects [-n] [-q] [-r] [--strict]";
@@ -639,18 +640,9 @@ int cmd_unpack_objects(int argc, const char **argv, const char *prefix UNUSED)
640 continue;
641 }
642 if (starts_with(arg, "--pack_header=")) {
642 - struct pack_header *hdr;
643 - char *c;
644 -
645 - hdr = (struct pack_header *)buffer;
646 - hdr->hdr_signature = htonl(PACK_SIGNATURE);
647 - hdr->hdr_version = htonl(strtoul(arg + 14, &c, 10));
648 - if (*c != ',')
649 - die("bad %s", arg);
650 - hdr->hdr_entries = htonl(strtoul(c + 1, &c, 10));
651 - if (*c)
652 - die("bad %s", arg);
653 - len = sizeof(*hdr);
643 + if (parse_pack_header_option(arg + 14,
644 + buffer, &len) < 0)
645 + die(_("bad %s"), arg);
646 continue;
647 }
648 if (skip_prefix(arg, "--max-input-size=", &arg)) {
packfile.c
+17
@@ -2294,3 +2294,20 @@ int is_promisor_object(const struct object_id *oid)
2294 }
2295 return oidset_contains(&promisor_objects, oid);
2296 }
2297 +
2298 +int parse_pack_header_option(const char *in, unsigned char *out, unsigned int *len)
2299 +{
2300 + struct pack_header *hdr;
2301 + char *c;
2302 +
2303 + hdr = (struct pack_header *)out;
2304 + hdr->hdr_signature = htonl(PACK_SIGNATURE);
2305 + hdr->hdr_version = htonl(strtoul(in, &c, 10));
2306 + if (*c != ',')
2307 + return -1;
2308 + hdr->hdr_entries = htonl(strtoul(c + 1, &c, 10));
2309 + if (*c)
2310 + return -1;
2311 + *len = sizeof(*hdr);
2312 + return 0;
2313 +}
packfile.h
+6
@@ -210,4 +210,10 @@ int is_promisor_object(const struct object_id *oid);
210 int load_idx(const char *path, const unsigned int hashsz, void *idx_map,
211 size_t idx_size, struct packed_git *p);
212
213 +/*
214 + * Parse a --pack_header option as accepted by index-pack and unpack-objects,
215 + * turning it into the matching bytes we'd find in a pack.
216 + */
217 +int parse_pack_header_option(const char *in, unsigned char *out, unsigned int *len);
218 +
219 #endif