object-file API: add a format_object_header() function

Add a convenience function to wrap the xsnprintf() command that generates loose object headers. This code was copy/pasted in various parts of the codebase, let's define it in one place and re-use it from there. All except one caller of it had a valid "enum object_type" for us, it's only write_object_file_prepare() which might need to deal with "git hash-object --literally" and a potential garbage type. Let's have the primary API use an "enum object_type", and define a *_literally() function that can take an arbitrary "const char *" for the type. See [1] for the discussion that prompted this patch, i.e. new code in object-file.c that wanted to copy/paste the xsnprintf() invocation. In the case of fast-import.c the callers unfortunately need to cast back & forth between "unsigned char *" and "char *", since format_object_header() ad encode_in_pack_object_header() take different signedness. 1. https://lore.kernel.org/git/211213.86bl1l9bfz.gmgdl@evledraar.gmail.com/ Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com> Signed-off-by: Jiang Xin <zhiyou.jx@alibaba-inc.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Ævar Arnfjörð Bjarmason committed Feb 5, 2022 at 00:48 UTC b04cdea46cf5ae60066fa6dd12d5449bf3ef283f
6 files changed +35 -11
builtin/fast-import.c
+3 -3
@@ -937,8 +937,8 @@ static int store_object(
937 git_hash_ctx c;
938 git_zstream s;
939
940 - hdrlen = xsnprintf((char *)hdr, sizeof(hdr), "%s %lu",
941 - type_name(type), (unsigned long)dat->len) + 1;
940 + hdrlen = format_object_header((char *)hdr, sizeof(hdr), type,
941 + dat->len);
942 the_hash_algo->init_fn(&c);
943 the_hash_algo->update_fn(&c, hdr, hdrlen);
944 the_hash_algo->update_fn(&c, dat->buf, dat->len);
@@ -1091,7 +1091,7 @@ static void stream_blob(uintmax_t len, struct object_id *oidout, uintmax_t mark)
1091 hashfile_checkpoint(pack_file, &checkpoint);
1092 offset = checkpoint.offset;
1093
1094 - hdrlen = xsnprintf((char *)out_buf, out_sz, "blob %" PRIuMAX, len) + 1;
1094 + hdrlen = format_object_header((char *)out_buf, out_sz, OBJ_BLOB, len);
1095
1096 the_hash_algo->init_fn(&c);
1097 the_hash_algo->update_fn(&c, out_buf, hdrlen);
builtin/index-pack.c
+1 -2
@@ -449,8 +449,7 @@ static void *unpack_entry_data(off_t offset, unsigned long size,
449 int hdrlen;
450
451 if (!is_delta_type(type)) {
452 - hdrlen = xsnprintf(hdr, sizeof(hdr), "%s %"PRIuMAX,
453 - type_name(type),(uintmax_t)size) + 1;
452 + hdrlen = format_object_header(hdr, sizeof(hdr), type, size);
453 the_hash_algo->init_fn(&c);
454 the_hash_algo->update_fn(&c, hdr, hdrlen);
455 } else
bulk-checkin.c
+2 -2
@@ -220,8 +220,8 @@ static int deflate_to_pack(struct bulk_checkin_state *state,
220 if (seekback == (off_t) -1)
221 return error("cannot find the current offset");
222
223 - header_len = xsnprintf((char *)obuf, sizeof(obuf), "%s %" PRIuMAX,
224 - type_name(type), (uintmax_t)size) + 1;
223 + header_len = format_object_header((char *)obuf, sizeof(obuf),
224 + type, size);
225 the_hash_algo->init_fn(&ctx);
226 the_hash_algo->update_fn(&ctx, obuf, header_len);
227
http-push.c
+1 -1
@@ -363,7 +363,7 @@ static void start_put(struct transfer_request *request)
363 git_zstream stream;
364
365 unpacked = read_object_file(&request->obj->oid, &type, &len);
366 - hdrlen = xsnprintf(hdr, sizeof(hdr), "%s %"PRIuMAX , type_name(type), (uintmax_t)len) + 1;
366 + hdrlen = format_object_header(hdr, sizeof(hdr), type, len);
367
368 /* Set it up */
369 git_deflate_init(&stream, zlib_compression_level);
object-file.c
+20 -3
@@ -1049,6 +1049,23 @@ void *xmmap(void *start, size_t length,
1049 return ret;
1050 }
1051
1052 +static int format_object_header_literally(char *str, size_t size,
1053 + const char *type, size_t objsize)
1054 +{
1055 + return xsnprintf(str, size, "%s %"PRIuMAX, type, (uintmax_t)objsize) + 1;
1056 +}
1057 +
1058 +int format_object_header(char *str, size_t size, enum object_type type,
1059 + size_t objsize)
1060 +{
1061 + const char *name = type_name(type);
1062 +
1063 + if (!name)
1064 + BUG("could not get a type name for 'enum object_type' value %d", type);
1065 +
1066 + return format_object_header_literally(str, size, name, objsize);
1067 +}
1068 +
1069 /*
1070 * With an in-core object data in "map", rehash it to make sure the
1071 * object name actually matches "oid" to detect object corruption.
@@ -1077,7 +1094,7 @@ int check_object_signature(struct repository *r, const struct object_id *oid,
1094 return -1;
1095
1096 /* Generate the header */
1080 - hdrlen = xsnprintf(hdr, sizeof(hdr), "%s %"PRIuMAX , type_name(obj_type), (uintmax_t)size) + 1;
1097 + hdrlen = format_object_header(hdr, sizeof(hdr), obj_type, size);
1098
1099 /* Sha1.. */
1100 r->hash_algo->init_fn(&c);
@@ -1777,7 +1794,7 @@ static void write_object_file_prepare(const struct git_hash_algo *algo,
1794 git_hash_ctx c;
1795
1796 /* Generate the header */
1780 - *hdrlen = xsnprintf(hdr, *hdrlen, "%s %"PRIuMAX , type, (uintmax_t)len)+1;
1797 + *hdrlen = format_object_header_literally(hdr, *hdrlen, type, len);
1798
1799 /* Sha1.. */
1800 algo->init_fn(&c);
@@ -2051,7 +2068,7 @@ int force_object_loose(const struct object_id *oid, time_t mtime)
2068 buf = read_object(the_repository, oid, &type, &len);
2069 if (!buf)
2070 return error(_("cannot read object for %s"), oid_to_hex(oid));
2054 - hdrlen = xsnprintf(hdr, sizeof(hdr), "%s %"PRIuMAX , type_name(type), (uintmax_t)len) + 1;
2071 + hdrlen = format_object_header(hdr, sizeof(hdr), type, len);
2072 ret = write_loose_object(oid, hdr, hdrlen, buf, len, mtime, 0);
2073 free(buf);
2074
object-store.h
+8
@@ -331,6 +331,14 @@ int repo_has_object_file_with_flags(struct repository *r,
331 */
332 int has_loose_object_nonlocal(const struct object_id *);
333
334 +/**
335 + * format_object_header() is a thin wrapper around s xsnprintf() that
336 + * writes the initial "<type> <obj-len>" part of the loose object
337 + * header. It returns the size that snprintf() returns + 1.
338 + */
339 +int format_object_header(char *str, size_t size, enum object_type type,
340 + size_t objsize);
341 +
342 void assert_oid_type(const struct object_id *oid, enum object_type expect);
343
344 /*