packfile: widen unpack_entry()'s size out-parameter to size_t

The topic `js/objects-larger-than-4gb-on-windows` widened the streaming, index-pack and unpack-objects paths to `size_t` but deliberately stopped at the in-memory `unpack_entry()` cascade, which still hands back the unpacked size through `unsigned long *`. On Windows that boundary truncates above 4 GiB because that data type is only 32 bits wide on that platform. Widen the code path. Except `packed_object_info_with_index_pos()`: It cannot yet pass `oi->sizep` directly because the field is still `unsigned long *`; bridge it with a `size_t` temporary that narrows back, and let a later commit drop the bridge once the field is wide too. `gfi_unpack_entry()` keeps its narrow signature because fast-import tracks sizes through `unsigned long` everywhere it crosses subsystem boundaries, keeping its signature allows the scope of this commit to be somewhat reasonable, still. Assisted-by: Opus 4.7 Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Johannes Schindelin committed Jun 15, 2026 at 11:52 UTC 2d83cc3f84594dc1fb79626c3eae4af3e942e882
4 files changed +27 -16
builtin/fast-import.c
+6 -1
@@ -1239,6 +1239,8 @@ static void *gfi_unpack_entry(
1239 unsigned long *sizep)
1240 {
1241 enum object_type type;
1242 + size_t size_st = 0;
1243 + void *data;
1244 struct packed_git *p = all_packs[oe->pack_id];
1245 if (p == pack_data && p->pack_size < (pack_size + the_hash_algo->rawsz)) {
1246 /* The object is stored in the packfile we are writing to
@@ -1260,7 +1262,10 @@ static void *gfi_unpack_entry(
1262 */
1263 p->pack_size = pack_size + the_hash_algo->rawsz;
1264 }
1263 - return unpack_entry(the_repository, p, oe->idx.offset, &type, sizep);
1265 + data = unpack_entry(the_repository, p, oe->idx.offset, &type, &size_st);
1266 + if (sizep)
1267 + *sizep = cast_size_t_to_ulong(size_st);
1268 + return data;
1269 }
1270
1271 static void load_tree(struct tree_entry *root)
pack-check.c
+2 -3
@@ -143,9 +143,8 @@ static int verify_packfile(struct repository *r,
143 data = NULL;
144 data_valid = 0;
145 } else {
146 - unsigned long sz;
147 - data = unpack_entry(r, p, entries[i].offset, &type, &sz);
148 - size = sz;
146 + data = unpack_entry(r, p, entries[i].offset, &type,
147 + &size);
148 data_valid = 1;
149 }
150
packfile.c
+17 -11
@@ -1454,7 +1454,7 @@ struct delta_base_cache_entry {
1454 struct delta_base_cache_key key;
1455 struct list_head lru;
1456 void *data;
1457 - unsigned long size;
1457 + size_t size;
1458 enum object_type type;
1459 };
1460
@@ -1525,7 +1525,7 @@ static void detach_delta_base_cache_entry(struct delta_base_cache_entry *ent)
1525 }
1526
1527 static void *cache_or_unpack_entry(struct repository *r, struct packed_git *p,
1528 - off_t base_offset, unsigned long *base_size,
1528 + off_t base_offset, size_t *base_size,
1529 enum object_type *type)
1530 {
1531 struct delta_base_cache_entry *ent;
@@ -1558,8 +1558,8 @@ void clear_delta_base_cache(void)
1558 }
1559
1560 static void add_delta_base_cache(struct packed_git *p, off_t base_offset,
1561 - void *base, unsigned long base_size,
1562 - unsigned long delta_base_cache_limit,
1561 + void *base, size_t base_size,
1562 + size_t delta_base_cache_limit,
1563 enum object_type type)
1564 {
1565 struct delta_base_cache_entry *ent;
@@ -1614,10 +1614,13 @@ static int packed_object_info_with_index_pos(struct packed_git *p, off_t obj_off
1614 * a "real" type later if the caller is interested.
1615 */
1616 if (oi->contentp) {
1617 - *oi->contentp = cache_or_unpack_entry(p->repo, p, obj_offset, oi->sizep,
1618 - &type);
1617 + size_t size_st = 0;
1618 + *oi->contentp = cache_or_unpack_entry(p->repo, p, obj_offset,
1619 + &size_st, &type);
1620 if (!*oi->contentp)
1621 type = OBJ_BAD;
1622 + else if (oi->sizep)
1623 + *oi->sizep = cast_size_t_to_ulong(size_st);
1624 } else if (oi->sizep || oi->typep || oi->delta_base_oid) {
1625 type = unpack_object_header(p, &w_curs, &curpos, &size);
1626 }
@@ -1735,7 +1738,7 @@ int packed_object_info(struct packed_git *p, off_t obj_offset,
1738 static void *unpack_compressed_entry(struct packed_git *p,
1739 struct pack_window **w_curs,
1740 off_t curpos,
1738 - unsigned long size)
1741 + size_t size)
1742 {
1743 int st;
1744 git_zstream stream;
@@ -1790,11 +1793,11 @@ int do_check_packed_object_crc;
1793 struct unpack_entry_stack_ent {
1794 off_t obj_offset;
1795 off_t curpos;
1793 - unsigned long size;
1796 + size_t size;
1797 };
1798
1799 void *unpack_entry(struct repository *r, struct packed_git *p, off_t obj_offset,
1797 - enum object_type *final_type, unsigned long *final_size)
1800 + enum object_type *final_type, size_t *final_size)
1801 {
1802 struct pack_window *w_curs = NULL;
1803 off_t curpos = obj_offset;
@@ -1911,7 +1914,7 @@ void *unpack_entry(struct repository *r, struct packed_git *p, off_t obj_offset,
1914 void *delta_data;
1915 void *base = data;
1916 void *external_base = NULL;
1914 - unsigned long delta_size, base_size = size;
1917 + size_t delta_size, base_size = size;
1918 int i;
1919 off_t base_obj_offset = obj_offset;
1920
@@ -1928,6 +1931,7 @@ void *unpack_entry(struct repository *r, struct packed_git *p, off_t obj_offset,
1931 struct object_id base_oid;
1932 if (!(offset_to_pack_pos(p, obj_offset, &pos))) {
1933 struct object_info oi = OBJECT_INFO_INIT;
1934 + unsigned long bsz_ul = 0;
1935
1936 nth_packed_object_id(&base_oid, p,
1937 pack_pos_to_index(p, pos));
@@ -1938,11 +1942,13 @@ void *unpack_entry(struct repository *r, struct packed_git *p, off_t obj_offset,
1942 mark_bad_packed_object(p, &base_oid);
1943
1944 oi.typep = &type;
1941 - oi.sizep = &base_size;
1945 + oi.sizep = &bsz_ul;
1946 oi.contentp = &base;
1947 if (odb_read_object_info_extended(r->objects, &base_oid,
1948 &oi, 0) < 0)
1949 base = NULL;
1950 + else
1951 + base_size = bsz_ul;
1952
1953 external_base = base;
1954 }
packfile.h
+2 -1
@@ -455,7 +455,8 @@ off_t nth_packed_object_offset(const struct packed_git *, uint32_t n);
455 off_t find_pack_entry_one(const struct object_id *oid, struct packed_git *);
456
457 int is_pack_valid(struct packed_git *);
458 -void *unpack_entry(struct repository *r, struct packed_git *, off_t, enum object_type *, unsigned long *);
458 +void *unpack_entry(struct repository *r, struct packed_git *, off_t,
459 + enum object_type *, size_t *);
460 unsigned long unpack_object_header_buffer(const unsigned char *buf, unsigned long len, enum object_type *type, size_t *sizep);
461 unsigned long get_size_from_delta(struct packed_git *, struct pack_window **, off_t);
462 int unpack_object_header(struct packed_git *, struct pack_window **, off_t *, size_t *);