{"thread":{"id":"65750","subject":"[PATCH 0/7] More work supporting objects larger than 4GB on Windows","startedAt":"2026-06-04T10:51:16Z","lastAt":"2026-06-18T15:08:55Z","messageCount":29,"participants":["Johannes Schindelin via GitGitGadget","Patrick Steinhardt","Johannes Schindelin","Junio C Hamano"],"isPatch":true,"patchVersion":1,"patchTotal":7},"messages":[{"id":"544716","messageId":"pull.2137.git.1780570272.gitgitgadget@gmail.com","threadId":"65750","inReplyTo":null,"subject":"[PATCH 0/7] More work supporting objects larger than 4GB on Windows","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2026-06-04T10:51:05Z","receivedAt":"2026-06-04T10:51:16Z","isPatch":true,"body":"This patch series tries to address the problems pointed out by the expensive\ntests that now run in CI: t5608 and t7508 verify various aspects about\nobjects larger than 4GB, which Git does not currently handle correctly when\nrun on a platform where size_t is 64-bit and unsigned long is 32-bit.\n\nUnfortunately, this conflicts heavily with ps/odb-source-loose. I rebased\nthe branch onto seen and pushed the result to\nhttps://github.com/dscho/git/tree/refs/heads/objects-larger-than-4gb-on-windows-pt2-seen,\nto make it easier to resolve merge conflicts. Here is the relevant\nrange-diff:\n\n1:  f3aeae983a ! 1:  62adeb9818 odb: use size_t for object_info.sizep and the size APIs\n    @@ builtin/log.c: static int show_blob_object(const struct object_id *oid, struct r\n     \n      ## builtin/ls-files.c ##\n     @@ builtin/ls-files.c: static void expand_objectsize(struct repository *repo, struct strbuf *line,\n    - \t\t\t      const enum object_type type, unsigned int padded)\n    - {\n    + \tsize_t len;\n    + \n      \tif (type == OBJ_BLOB) {\n     -\t\tunsigned long size;\n     +\t\tsize_t size;\n    @@ builtin/ls-files.c: static void expand_objectsize(struct repository *repo, struc\n     \n      ## builtin/ls-tree.c ##\n     @@ builtin/ls-tree.c: static void expand_objectsize(struct strbuf *line, const struct object_id *oid,\n    - \t\t\t      const enum object_type type, unsigned int padded)\n    - {\n    + \tsize_t len;\n    + \n      \tif (type == OBJ_BLOB) {\n     -\t\tunsigned long size;\n     +\t\tsize_t size;\n    @@ notes.c: static void format_note(struct notes_tree *t, const struct object_id *o\n      \tif (!t)\n     \n      ## object-file.c ##\n    -@@ object-file.c: static int parse_loose_header(const char *hdr, struct object_info *oi)\n    +@@ object-file.c: int parse_loose_header(const char *hdr, struct object_info *oi)\n      \t}\n      \n      \tif (oi->sizep)\n    @@ object-file.c: static int parse_loose_header(const char *hdr, struct object_info\n      \n      \t/*\n      \t * The length must be followed by a zero byte\n    -@@ object-file.c: static int read_object_info_from_path(struct odb_source *source,\n    - \tvoid *map = NULL;\n    - \tgit_zstream stream, *stream_to_end = NULL;\n    - \tchar hdr[MAX_HEADER_LEN];\n    --\tunsigned long size_scratch;\n    -+\tsize_t size_scratch;\n    - \tenum object_type type_scratch;\n    - \tstruct stat st;\n    - \n     @@ object-file.c: int force_object_loose(struct odb_source *source,\n    - {\n    + \tstruct odb_source_files *files = odb_source_files_downcast(source);\n      \tconst struct git_hash_algo *compat = source->odb->repo->compat_hash_algo;\n      \tvoid *buf;\n     -\tunsigned long len;\n    @@ object-file.c: int read_loose_object(struct repository *repo,\n      \n      \tfd = git_open(path);\n      \tif (fd >= 0)\n    -@@ object-file.c: int odb_source_loose_read_object_stream(struct odb_read_stream **out,\n    - \tstruct object_info oi = OBJECT_INFO_INIT;\n    - \tstruct odb_loose_read_stream *st;\n    - \tunsigned long mapsize;\n    --\tunsigned long size_ul;\n    - \tvoid *mapped;\n    - \n    - \tmapped = odb_source_loose_map_object(source, oid, &mapsize);\n    -@@ object-file.c: int odb_source_loose_read_object_stream(struct odb_read_stream **out,\n    - \t\tgoto error;\n    - \t}\n    - \n    --\t/*\n    --\t * object_info.sizep is unsigned long* (32-bit on Windows), but\n    --\t * st->base.size is size_t (64-bit). Use temporary variable.\n    --\t * Note: loose objects >4GB would still truncate here, but such\n    --\t * large loose objects are uncommon (they'd normally be packed).\n    --\t */\n    --\toi.sizep = &size_ul;\n    -+\toi.sizep = &st->base.size;\n    - \toi.typep = &st->base.type;\n    - \n    - \tif (parse_loose_header(st->hdr, &oi) < 0 || st->base.type < 0)\n    - \t\tgoto error;\n    --\tst->base.size = size_ul;\n    - \n    - \tst->mapped = mapped;\n    - \tst->mapsize = mapsize;\n     \n      ## object.c ##\n     @@ object.c: struct object *parse_object_with_flags(struct repository *r,\n    @@ odb.h: int odb_read_object_info_extended(struct object_database *odb,\n      enum odb_has_object_flags {\n      \t/* Retry packed storage after checking packed and loose storage */\n     \n    + ## odb/source-loose.c ##\n    +@@ odb/source-loose.c: static int read_object_info_from_path(struct odb_source_loose *loose,\n    + \tvoid *map = NULL;\n    + \tgit_zstream stream, *stream_to_end = NULL;\n    + \tchar hdr[MAX_HEADER_LEN];\n    +-\tunsigned long size_scratch;\n    ++\tsize_t size_scratch;\n    + \tenum object_type type_scratch;\n    + \tstruct stat st;\n    + \n    +@@ odb/source-loose.c: static int odb_source_loose_read_object_stream(struct odb_read_stream **out,\n    + \tstruct object_info oi = OBJECT_INFO_INIT;\n    + \tstruct odb_loose_read_stream *st;\n    + \tunsigned long mapsize;\n    +-\tunsigned long size_ul;\n    + \tvoid *mapped;\n    + \n    + \tmapped = odb_source_loose_map_object(loose, oid, &mapsize);\n    +@@ odb/source-loose.c: static int odb_source_loose_read_object_stream(struct odb_read_stream **out,\n    + \t\tgoto error;\n    + \t}\n    + \n    +-\t/*\n    +-\t * object_info.sizep is unsigned long* (32-bit on Windows), but\n    +-\t * st->base.size is size_t (64-bit). Use temporary variable.\n    +-\t * Note: loose objects >4GB would still truncate here, but such\n    +-\t * large loose objects are uncommon (they'd normally be packed).\n    +-\t */\n    +-\toi.sizep = &size_ul;\n    ++\toi.sizep = &st->base.size;\n    + \toi.typep = &st->base.type;\n    + \n    + \tif (parse_loose_header(st->hdr, &oi) < 0 || st->base.type < 0)\n    + \t\tgoto error;\n    +-\tst->base.size = size_ul;\n    + \n    + \tst->mapped = mapped;\n    + \tst->mapsize = mapsize;\n    +\n      ## odb/streaming.c ##\n     @@ odb/streaming.c: static int open_istream_incore(struct odb_read_stream **out,\n      \t\t.base.read = read_istream_incore,\n\n\nJohannes Schindelin (7):\n  compat/msvc: use _chsize_s for ftruncate\n  patch-delta: use size_t for sizes\n  pack-objects(check_pack_inflate()): use size_t instead of unsigned\n    long\n  packfile: widen unpack_entry()'s size out-parameter to size_t\n  pack-objects: use size_t for in-core object sizes\n  packfile,delta: drop the `cast_size_t_to_ulong()` wrappers\n  odb: use size_t for object_info.sizep and the size APIs\n\n apply.c                       |  8 ++--\n archive.c                     |  4 +-\n attr.c                        |  2 +-\n bisect.c                      |  2 +-\n blame.c                       | 15 +++++--\n builtin/cat-file.c            | 39 ++++++++++++-------\n builtin/difftool.c            |  2 +-\n builtin/fast-export.c         |  7 +++-\n builtin/fast-import.c         | 29 ++++++++++----\n builtin/fsck.c                |  2 +-\n builtin/grep.c                | 12 +++---\n builtin/index-pack.c          | 10 ++---\n builtin/log.c                 |  2 +-\n builtin/ls-files.c            |  2 +-\n builtin/ls-tree.c             |  4 +-\n builtin/merge-tree.c          |  6 +--\n builtin/mktag.c               |  2 +-\n builtin/notes.c               |  6 +--\n builtin/pack-objects.c        | 73 +++++++++++++++++++++--------------\n builtin/repo.c                |  4 +-\n builtin/tag.c                 |  4 +-\n builtin/unpack-file.c         |  2 +-\n builtin/unpack-objects.c      |  8 ++--\n bundle.c                      |  2 +-\n combine-diff.c                |  4 +-\n commit.c                      | 10 ++---\n compat/msvc-posix.h           | 24 +++++++++++-\n config.c                      |  2 +-\n delta.h                       | 20 +++-------\n diff.c                        |  5 ++-\n dir.c                         |  2 +-\n entry.c                       |  4 +-\n fmt-merge-msg.c               |  4 +-\n fsck.c                        |  2 +-\n grep.c                        |  4 +-\n http-push.c                   |  2 +-\n list-objects-filter.c         |  2 +-\n mailmap.c                     |  2 +-\n match-trees.c                 |  4 +-\n merge-blobs.c                 |  6 +--\n merge-blobs.h                 |  2 +-\n merge-ort.c                   |  2 +-\n notes-cache.c                 |  2 +-\n notes-merge.c                 |  2 +-\n notes.c                       |  8 ++--\n object-file.c                 | 18 +++------\n object.c                      |  2 +-\n odb.c                         | 12 +++---\n odb.h                         | 10 ++---\n odb/streaming.c               | 13 +------\n pack-bitmap.c                 |  4 +-\n pack-check.c                  |  5 +--\n pack-objects.h                |  2 +-\n packfile.c                    | 54 ++++++++++----------------\n packfile.h                    |  5 ++-\n patch-delta.c                 |  8 ++--\n path-walk.c                   |  2 +-\n protocol-caps.c               |  5 ++-\n read-cache.c                  |  6 +--\n ref-filter.c                  |  2 +-\n reflog.c                      |  2 +-\n rerere.c                      |  2 +-\n submodule-config.c            |  2 +-\n t/helper/test-delta.c         | 10 +++--\n t/helper/test-pack-deltas.c   |  3 +-\n t/helper/test-partial-clone.c |  2 +-\n t/unit-tests/u-odb-inmemory.c |  2 +-\n tag.c                         |  4 +-\n tree-walk.c                   | 10 +++--\n tree.c                        |  2 +-\n xdiff-interface.c             |  2 +-\n 71 files changed, 296 insertions(+), 253 deletions(-)\n\n\nbase-commit: 9ac3f193c05c2237e2b14ebaa1149e9fc8a1abe0\nPublished-As: https://github.com/gitgitgadget/git/releases/tag/pr-2137%2Fdscho%2Fobjects-larger-than-4gb-on-windows-pt2-v1\nFetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-2137/dscho/objects-larger-than-4gb-on-windows-pt2-v1\nPull-Request: https://github.com/gitgitgadget/git/pull/2137\n-- \ngitgitgadget\n"},{"id":"544717","messageId":"de9fc5c4556609ed1a8d61ce5207dc1ebcfbfecf.1780570273.git.gitgitgadget@gmail.com","threadId":"65750","inReplyTo":"pull.2137.git.1780570272.gitgitgadget@gmail.com","subject":"[PATCH 1/7] compat/msvc: use _chsize_s for ftruncate","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2026-06-04T10:51:06Z","receivedAt":"2026-06-04T10:51:17Z","isPatch":true,"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nOn Windows, `unsigned long` and `long` are 32 bits even on 64-bit\nbuilds. The MSVC compatibility header has shimmed `ftruncate()` with\n\n\t#define ftruncate _chsize\n\never since `compat/msvc-posix.h` was introduced. `_chsize()` takes a\n32-bit `long` for the new length, which silently truncates files (and\nthe requested size) to 2 GiB. That is enough to make t7508 test 126\n\"git add fails gracefully with 4 GiB and 8 GiB files\" fail under\nMSVC: `test-tool truncate` creates a sparse 4 GiB or 8 GiB file via\nthe shimmed `ftruncate()`, and the test never gets off the ground.\n\n`_chsize_s()` is the modern replacement, accepts a 64-bit `__int64`\nlength, and is the only sensible target on Windows. The catch is that\nit does not follow the POSIX `-1` + `errno` convention: it returns\n`0` on success and an errno value (a small positive integer) on\nfailure. A plain `#define ftruncate _chsize_s` would therefore\nsilently break callers that test the return value as `< 0` or against\n`-1`, of which there are several: `http.c`, `parallel-checkout.c`,\nand `t/helper/test-truncate.c` among them.\n\nIntroduce a `static inline` wrapper that calls `_chsize_s()`, copies\nits errno return into `errno`, and translates the result to the\nfamiliar `-1` / `0` convention, then point `ftruncate` at the\nwrapper. Place the wrapper after `#include \"mingw-posix.h\"` so the\n`off_t` parameter resolves to the already-widened `off64_t` rather\nthan the 32-bit `_off_t` from `compat/vcbuild/include/unistd.h`.\n\nMinGW is unaffected: its `ftruncate()` already takes `off_t` and\nroutes through `ftruncate64()` when `_FILE_OFFSET_BITS=64`, which is\nthe default in our build.\n\nAssisted-by: Opus 4.7\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n compat/msvc-posix.h | 24 +++++++++++++++++++++++-\n 1 file changed, 23 insertions(+), 1 deletion(-)\n\ndiff --git a/compat/msvc-posix.h b/compat/msvc-posix.h\nindex c500b8b4aa..7ce39b8d3f 100644\n--- a/compat/msvc-posix.h\n+++ b/compat/msvc-posix.h\n@@ -16,7 +16,6 @@\n #define __attribute__(x)\n #define strcasecmp   _stricmp\n #define strncasecmp  _strnicmp\n-#define ftruncate    _chsize\n #define strtoull     _strtoui64\n #define strtoll      _strtoi64\n \n@@ -30,4 +29,27 @@ typedef int sigset_t;\n \n #include \"mingw-posix.h\"\n \n+/*\n+ * MSVC's `_chsize()` takes a 32-bit `long` and silently truncates files\n+ * to 2 GiB. `_chsize_s()` accepts a 64-bit length but returns 0 on\n+ * success or an errno value on failure, rather than the -1/errno\n+ * convention POSIX `ftruncate()` callers expect. Wrap it so callers\n+ * that test the return value as `< 0` or against `-1` keep working.\n+ *\n+ * Note: this declaration must follow `#include \"mingw-posix.h\"` so\n+ * `off_t` resolves to `off64_t` and the parameter type matches the\n+ * underlying `_chsize_s()` width.\n+ */\n+static inline int msvc_ftruncate(int fd, off_t length)\n+{\n+\tint err = _chsize_s(fd, length);\n+\n+\tif (err) {\n+\t\terrno = err;\n+\t\treturn -1;\n+\t}\n+\treturn 0;\n+}\n+#define ftruncate msvc_ftruncate\n+\n #endif /* COMPAT_MSVC_POSIX_H */\n-- \ngitgitgadget\n\n"},{"id":"544718","messageId":"1fd7646ca14f7ec392c85fab10255f08d0d79368.1780570273.git.gitgitgadget@gmail.com","threadId":"65750","inReplyTo":"pull.2137.git.1780570272.gitgitgadget@gmail.com","subject":"[PATCH 2/7] patch-delta: use size_t for sizes","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2026-06-04T10:51:07Z","receivedAt":"2026-06-04T10:51:19Z","isPatch":true,"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\n`patch_delta()` takes the source and delta sizes by value and writes\nback the reconstructed target size through an `unsigned long *`.  That\ndatatype cannot represent a value that exceeds 4 GiB on systems where\n`unsigned long` is 32-bit (notably 64-bit Windows builds), though, even\nthough the delta encoding itself, the on-disk layout, and the in-memory\nbuffers happily carry such sizes. A `size_t` companion to\n`get_delta_hdr_size()`, `get_delta_hdr_size_sz()`, was introduced in\n17fa077596 (delta, packfile: use size_t for delta header sizes,\n2026-05-08) precisely so that `patch_delta()` could be widened without\nchanging the on-the-wire decoding helper's signature.\n\nWiden `patch_delta()`'s three size parameters to `size_t` and switch\nits internal use of `get_delta_hdr_size()` to the `_sz` variant.\nThen propagate the wider type through the callers.\n\nAssisted-by: Opus 4.7\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n apply.c                  |  2 +-\n builtin/index-pack.c     |  4 ++--\n builtin/unpack-objects.c |  2 +-\n delta.h                  |  6 +++---\n packfile.c               |  4 +---\n patch-delta.c            | 12 ++++++------\n t/helper/test-delta.c    | 10 ++++++----\n 7 files changed, 20 insertions(+), 20 deletions(-)\n\ndiff --git a/apply.c b/apply.c\nindex 249248d4f2..3cf544e9a9 100644\n--- a/apply.c\n+++ b/apply.c\n@@ -3232,7 +3232,7 @@ static int apply_binary_fragment(struct apply_state *state,\n \t\t\t\t struct patch *patch)\n {\n \tstruct fragment *fragment = patch->fragments;\n-\tunsigned long len;\n+\tsize_t len;\n \tvoid *dst;\n \n \tif (!fragment)\ndiff --git a/builtin/index-pack.c b/builtin/index-pack.c\nindex cf0bd8280d..3c4474e681 100644\n--- a/builtin/index-pack.c\n+++ b/builtin/index-pack.c\n@@ -71,7 +71,7 @@ struct base_data {\n \t/* Not initialized by make_base(). */\n \tstruct list_head list;\n \tvoid *data;\n-\tunsigned long size;\n+\tsize_t size;\n };\n \n /*\n@@ -1048,7 +1048,7 @@ static struct base_data *resolve_delta(struct object_entry *delta_obj,\n {\n \tvoid *delta_data, *result_data;\n \tstruct base_data *result;\n-\tunsigned long result_size;\n+\tsize_t result_size;\n \n \tif (show_stat) {\n \t\tint i = delta_obj - objects;\ndiff --git a/builtin/unpack-objects.c b/builtin/unpack-objects.c\nindex 59e9b8711e..e7a50c493c 100644\n--- a/builtin/unpack-objects.c\n+++ b/builtin/unpack-objects.c\n@@ -314,7 +314,7 @@ static void resolve_delta(unsigned nr, enum object_type type,\n \t\t\t  void *delta, unsigned long delta_size)\n {\n \tvoid *result;\n-\tunsigned long result_size;\n+\tsize_t result_size;\n \n \tresult = patch_delta(base, base_size,\n \t\t\t     delta, delta_size,\ndiff --git a/delta.h b/delta.h\nindex fad68cfc45..bb149dc82b 100644\n--- a/delta.h\n+++ b/delta.h\n@@ -75,9 +75,9 @@ diff_delta(const void *src_buf, unsigned long src_bufsize,\n  * *trg_bufsize is updated with its size.  On failure a NULL pointer is\n  * returned.  The returned buffer must be freed by the caller.\n  */\n-void *patch_delta(const void *src_buf, unsigned long src_size,\n-\t\t  const void *delta_buf, unsigned long delta_size,\n-\t\t  unsigned long *dst_size);\n+void *patch_delta(const void *src_buf, size_t src_size,\n+\t\t  const void *delta_buf, size_t delta_size,\n+\t\t  size_t *dst_size);\n \n /* the smallest possible delta size is 4 bytes */\n #define DELTA_SIZE_MIN\t4\ndiff --git a/packfile.c b/packfile.c\nindex 89366abfe3..e202f48837 100644\n--- a/packfile.c\n+++ b/packfile.c\n@@ -1964,10 +1964,8 @@ void *unpack_entry(struct repository *r, struct packed_git *p, off_t obj_offset,\n \t\t\t      (uintmax_t)curpos, p->pack_name);\n \t\t\tdata = NULL;\n \t\t} else {\n-\t\t\tunsigned long sz;\n \t\t\tdata = patch_delta(base, base_size, delta_data,\n-\t\t\t\t\t   delta_size, &sz);\n-\t\t\tsize = sz;\n+\t\t\t\t\t   delta_size, &size);\n \n \t\t\t/*\n \t\t\t * We could not apply the delta; warn the user, but\ndiff --git a/patch-delta.c b/patch-delta.c\nindex b5c8594db6..44cda97994 100644\n--- a/patch-delta.c\n+++ b/patch-delta.c\n@@ -12,13 +12,13 @@\n #include \"git-compat-util.h\"\n #include \"delta.h\"\n \n-void *patch_delta(const void *src_buf, unsigned long src_size,\n-\t\t  const void *delta_buf, unsigned long delta_size,\n-\t\t  unsigned long *dst_size)\n+void *patch_delta(const void *src_buf, size_t src_size,\n+\t\t  const void *delta_buf, size_t delta_size,\n+\t\t  size_t *dst_size)\n {\n \tconst unsigned char *data, *top;\n \tunsigned char *dst_buf, *out, cmd;\n-\tunsigned long size;\n+\tsize_t size;\n \n \tif (delta_size < DELTA_SIZE_MIN)\n \t\treturn NULL;\n@@ -27,12 +27,12 @@ void *patch_delta(const void *src_buf, unsigned long src_size,\n \ttop = (const unsigned char *) delta_buf + delta_size;\n \n \t/* make sure the orig file size matches what we expect */\n-\tsize = get_delta_hdr_size(&data, top);\n+\tsize = get_delta_hdr_size_sz(&data, top);\n \tif (size != src_size)\n \t\treturn NULL;\n \n \t/* now the result size */\n-\tsize = get_delta_hdr_size(&data, top);\n+\tsize = get_delta_hdr_size_sz(&data, top);\n \tdst_buf = xmallocz(size);\n \n \tout = dst_buf;\ndiff --git a/t/helper/test-delta.c b/t/helper/test-delta.c\nindex 52ea00c937..8223a60229 100644\n--- a/t/helper/test-delta.c\n+++ b/t/helper/test-delta.c\n@@ -21,7 +21,7 @@ int cmd__delta(int argc, const char **argv)\n \tint fd;\n \tstruct strbuf from = STRBUF_INIT, data = STRBUF_INIT;\n \tchar *out_buf;\n-\tunsigned long out_size;\n+\tsize_t out_size;\n \n \tif (argc != 5 || (strcmp(argv[1], \"-d\") && strcmp(argv[1], \"-p\")))\n \t\tusage(usage_str);\n@@ -31,11 +31,13 @@ int cmd__delta(int argc, const char **argv)\n \tif (strbuf_read_file(&data, argv[3], 0) < 0)\n \t\tdie_errno(\"unable to read '%s'\", argv[3]);\n \n-\tif (argv[1][1] == 'd')\n+\tif (argv[1][1] == 'd') {\n+\t\tunsigned long delta_size;\n \t\tout_buf = diff_delta(from.buf, from.len,\n \t\t\t\t     data.buf, data.len,\n-\t\t\t\t     &out_size, 0);\n-\telse\n+\t\t\t\t     &delta_size, 0);\n+\t\tout_size = delta_size;\n+\t} else\n \t\tout_buf = patch_delta(from.buf, from.len,\n \t\t\t\t      data.buf, data.len,\n \t\t\t\t      &out_size);\n-- \ngitgitgadget\n\n"},{"id":"544719","messageId":"ddb75326cde9695f1eb7bbbe77175424e6b77004.1780570273.git.gitgitgadget@gmail.com","threadId":"65750","inReplyTo":"pull.2137.git.1780570272.gitgitgadget@gmail.com","subject":"[PATCH 3/7] pack-objects(check_pack_inflate()): use size_t instead of unsigned long","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2026-06-04T10:51:08Z","receivedAt":"2026-06-04T10:51:20Z","isPatch":true,"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\n`write_reuse_object()` learned to track its packed-object size as\n`size_t` in 606c192380 (odb, packfile: use size_t for streaming\nobject sizes, 2026-05-08), but the comparison sink it feeds,\n`check_pack_inflate()`, still takes the expected decompressed size\nas `unsigned long`. The call site bridges the mismatch with\n`cast_size_t_to_ulong()`, which on Windows turns a >4 GiB object\ninto an immediate die().\n\nThat function only uses `expect` once: as the right-hand side of a\n`stream.total_out == expect` equality test against zlib's counter.\nzlib's own `total_out` counter is `uLong` and is therefore still\n32-bit-bound on Windows. Widening `expect` to `size_t` cannot fix that,\nbut it is a strict improvement nonetheless: instead of dying outright,\nan oversized object now simply makes the equality fail and lets\n`write_reuse_object()` fall back to `write_no_reuse_object()`, which\ndecompresses and re-deflates the content (and which the larger\npack-objects widening series targets separately).\n\nDrop the `cast_size_t_to_ulong()` shim at the call site now that\nthe receiving parameter speaks the same type as `entry_size`.\n\nAssisted-by: Opus 4.7\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n builtin/pack-objects.c | 5 ++---\n 1 file changed, 2 insertions(+), 3 deletions(-)\n\ndiff --git a/builtin/pack-objects.c b/builtin/pack-objects.c\nindex fe9fbecb30..975f04d699 100644\n--- a/builtin/pack-objects.c\n+++ b/builtin/pack-objects.c\n@@ -453,7 +453,7 @@ static int check_pack_inflate(struct packed_git *p,\n \t\tstruct pack_window **w_curs,\n \t\toff_t offset,\n \t\toff_t len,\n-\t\tunsigned long expect)\n+\t\tsize_t expect)\n {\n \tgit_zstream stream;\n \tunsigned char fakebuf[4096], *in;\n@@ -671,8 +671,7 @@ static off_t write_reuse_object(struct hashfile *f, struct object_entry *entry,\n \tdatalen -= entry->in_pack_header_size;\n \n \tif (!pack_to_stdout && p->index_version == 1 &&\n-\t    check_pack_inflate(p, &w_curs, offset, datalen,\n-\t\t\t       cast_size_t_to_ulong(entry_size))) {\n+\t    check_pack_inflate(p, &w_curs, offset, datalen, entry_size)) {\n \t\terror(_(\"corrupt packed object for %s\"),\n \t\t      oid_to_hex(&entry->idx.oid));\n \t\tunuse_pack(&w_curs);\n-- \ngitgitgadget\n\n"},{"id":"544720","messageId":"bdebc36f21d1e2a13bc91d72a3ada1db3f7e184e.1780570273.git.gitgitgadget@gmail.com","threadId":"65750","inReplyTo":"pull.2137.git.1780570272.gitgitgadget@gmail.com","subject":"[PATCH 4/7] packfile: widen unpack_entry()'s size out-parameter to size_t","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2026-06-04T10:51:09Z","receivedAt":"2026-06-04T10:51:21Z","isPatch":true,"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nThe topic `js/objects-larger-than-4gb-on-windows` widened the streaming,\nindex-pack and unpack-objects paths to `size_t` but deliberately stopped\nat the in-memory `unpack_entry()` cascade, which still hands back the\nunpacked size through `unsigned long *`.  On Windows that boundary\ntruncates above 4 GiB because that data type is only 32 bits wide on\nthat platform.\n\nWiden the code path. Except `packed_object_info_with_index_pos()`: It\ncannot yet pass `oi->sizep` directly because the field is still\n`unsigned long *`; bridge it with a `size_t` temporary that narrows\nback, and let a later commit drop the bridge once the field is wide\ntoo. `gfi_unpack_entry()` keeps its narrow signature because fast-import\ntracks sizes through `unsigned long` everywhere it crosses subsystem\nboundaries, keeping its signature allows the scope of this commit to be\nsomewhat reasonable, still.\n\nAssisted-by: Opus 4.7\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n builtin/fast-import.c |  7 ++++++-\n pack-check.c          |  5 ++---\n packfile.c            | 28 +++++++++++++++++-----------\n packfile.h            |  3 ++-\n 4 files changed, 27 insertions(+), 16 deletions(-)\n\ndiff --git a/builtin/fast-import.c b/builtin/fast-import.c\nindex 82bc6dcc00..3dff898c43 100644\n--- a/builtin/fast-import.c\n+++ b/builtin/fast-import.c\n@@ -1239,6 +1239,8 @@ static void *gfi_unpack_entry(\n \tunsigned long *sizep)\n {\n \tenum object_type type;\n+\tsize_t size_st = 0;\n+\tvoid *data;\n \tstruct packed_git *p = all_packs[oe->pack_id];\n \tif (p == pack_data && p->pack_size < (pack_size + the_hash_algo->rawsz)) {\n \t\t/* The object is stored in the packfile we are writing to\n@@ -1260,7 +1262,10 @@ static void *gfi_unpack_entry(\n \t\t */\n \t\tp->pack_size = pack_size + the_hash_algo->rawsz;\n \t}\n-\treturn unpack_entry(the_repository, p, oe->idx.offset, &type, sizep);\n+\tdata = unpack_entry(the_repository, p, oe->idx.offset, &type, &size_st);\n+\tif (sizep)\n+\t\t*sizep = cast_size_t_to_ulong(size_st);\n+\treturn data;\n }\n \n static void load_tree(struct tree_entry *root)\ndiff --git a/pack-check.c b/pack-check.c\nindex 2792f34d25..5adfb3f272 100644\n--- a/pack-check.c\n+++ b/pack-check.c\n@@ -143,9 +143,8 @@ static int verify_packfile(struct repository *r,\n \t\t\tdata = NULL;\n \t\t\tdata_valid = 0;\n \t\t} else {\n-\t\t\tunsigned long sz;\n-\t\t\tdata = unpack_entry(r, p, entries[i].offset, &type, &sz);\n-\t\t\tsize = sz;\n+\t\t\tdata = unpack_entry(r, p, entries[i].offset, &type,\n+\t\t\t\t\t    &size);\n \t\t\tdata_valid = 1;\n \t\t}\n \ndiff --git a/packfile.c b/packfile.c\nindex e202f48837..dab0a9b16d 100644\n--- a/packfile.c\n+++ b/packfile.c\n@@ -1454,7 +1454,7 @@ struct delta_base_cache_entry {\n \tstruct delta_base_cache_key key;\n \tstruct list_head lru;\n \tvoid *data;\n-\tunsigned long size;\n+\tsize_t size;\n \tenum object_type type;\n };\n \n@@ -1525,7 +1525,7 @@ static void detach_delta_base_cache_entry(struct delta_base_cache_entry *ent)\n }\n \n static void *cache_or_unpack_entry(struct repository *r, struct packed_git *p,\n-\t\t\t\t   off_t base_offset, unsigned long *base_size,\n+\t\t\t\t   off_t base_offset, size_t *base_size,\n \t\t\t\t   enum object_type *type)\n {\n \tstruct delta_base_cache_entry *ent;\n@@ -1558,8 +1558,8 @@ void clear_delta_base_cache(void)\n }\n \n static void add_delta_base_cache(struct packed_git *p, off_t base_offset,\n-\t\t\t\t void *base, unsigned long base_size,\n-\t\t\t\t unsigned long delta_base_cache_limit,\n+\t\t\t\t void *base, size_t base_size,\n+\t\t\t\t size_t delta_base_cache_limit,\n \t\t\t\t enum object_type type)\n {\n \tstruct delta_base_cache_entry *ent;\n@@ -1614,10 +1614,13 @@ static int packed_object_info_with_index_pos(struct packed_git *p, off_t obj_off\n \t * a \"real\" type later if the caller is interested.\n \t */\n \tif (oi->contentp) {\n-\t\t*oi->contentp = cache_or_unpack_entry(p->repo, p, obj_offset, oi->sizep,\n-\t\t\t\t\t\t      &type);\n+\t\tsize_t size_st = 0;\n+\t\t*oi->contentp = cache_or_unpack_entry(p->repo, p, obj_offset,\n+\t\t\t\t\t\t      &size_st, &type);\n \t\tif (!*oi->contentp)\n \t\t\ttype = OBJ_BAD;\n+\t\telse if (oi->sizep)\n+\t\t\t*oi->sizep = cast_size_t_to_ulong(size_st);\n \t} else if (oi->sizep || oi->typep || oi->delta_base_oid) {\n \t\ttype = unpack_object_header(p, &w_curs, &curpos, &size);\n \t}\n@@ -1735,7 +1738,7 @@ int packed_object_info(struct packed_git *p, off_t obj_offset,\n static void *unpack_compressed_entry(struct packed_git *p,\n \t\t\t\t    struct pack_window **w_curs,\n \t\t\t\t    off_t curpos,\n-\t\t\t\t    unsigned long size)\n+\t\t\t\t    size_t size)\n {\n \tint st;\n \tgit_zstream stream;\n@@ -1790,11 +1793,11 @@ int do_check_packed_object_crc;\n struct unpack_entry_stack_ent {\n \toff_t obj_offset;\n \toff_t curpos;\n-\tunsigned long size;\n+\tsize_t size;\n };\n \n void *unpack_entry(struct repository *r, struct packed_git *p, off_t obj_offset,\n-\t\t   enum object_type *final_type, unsigned long *final_size)\n+\t\t   enum object_type *final_type, size_t *final_size)\n {\n \tstruct pack_window *w_curs = NULL;\n \toff_t curpos = obj_offset;\n@@ -1911,7 +1914,7 @@ void *unpack_entry(struct repository *r, struct packed_git *p, off_t obj_offset,\n \t\tvoid *delta_data;\n \t\tvoid *base = data;\n \t\tvoid *external_base = NULL;\n-\t\tunsigned long delta_size, base_size = size;\n+\t\tsize_t delta_size, base_size = size;\n \t\tint i;\n \t\toff_t base_obj_offset = obj_offset;\n \n@@ -1928,6 +1931,7 @@ void *unpack_entry(struct repository *r, struct packed_git *p, off_t obj_offset,\n \t\t\tstruct object_id base_oid;\n \t\t\tif (!(offset_to_pack_pos(p, obj_offset, &pos))) {\n \t\t\t\tstruct object_info oi = OBJECT_INFO_INIT;\n+\t\t\t\tunsigned long bsz_ul = 0;\n \n \t\t\t\tnth_packed_object_id(&base_oid, p,\n \t\t\t\t\t\t     pack_pos_to_index(p, pos));\n@@ -1938,11 +1942,13 @@ void *unpack_entry(struct repository *r, struct packed_git *p, off_t obj_offset,\n \t\t\t\tmark_bad_packed_object(p, &base_oid);\n \n \t\t\t\toi.typep = &type;\n-\t\t\t\toi.sizep = &base_size;\n+\t\t\t\toi.sizep = &bsz_ul;\n \t\t\t\toi.contentp = &base;\n \t\t\t\tif (odb_read_object_info_extended(r->objects, &base_oid,\n \t\t\t\t\t\t\t\t  &oi, 0) < 0)\n \t\t\t\t\tbase = NULL;\n+\t\t\t\telse\n+\t\t\t\t\tbase_size = bsz_ul;\n \n \t\t\t\texternal_base = base;\n \t\t\t}\ndiff --git a/packfile.h b/packfile.h\nindex 49d6bdecf6..0b5ae3f9fc 100644\n--- a/packfile.h\n+++ b/packfile.h\n@@ -455,7 +455,8 @@ off_t nth_packed_object_offset(const struct packed_git *, uint32_t n);\n off_t find_pack_entry_one(const struct object_id *oid, struct packed_git *);\n \n int is_pack_valid(struct packed_git *);\n-void *unpack_entry(struct repository *r, struct packed_git *, off_t, enum object_type *, unsigned long *);\n+void *unpack_entry(struct repository *r, struct packed_git *, off_t,\n+\t\t   enum object_type *, size_t *);\n unsigned long unpack_object_header_buffer(const unsigned char *buf, unsigned long len, enum object_type *type, size_t *sizep);\n unsigned long get_size_from_delta(struct packed_git *, struct pack_window **, off_t);\n int unpack_object_header(struct packed_git *, struct pack_window **, off_t *, size_t *);\n-- \ngitgitgadget\n\n"},{"id":"544721","messageId":"68750ba2d112073b2f3bd2998ee01a4cdd2fb904.1780570273.git.gitgitgadget@gmail.com","threadId":"65750","inReplyTo":"pull.2137.git.1780570272.gitgitgadget@gmail.com","subject":"[PATCH 5/7] pack-objects: use size_t for in-core object sizes","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2026-06-04T10:51:10Z","receivedAt":"2026-06-04T10:51:25Z","isPatch":true,"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\n`pack-objects` stores per-entry object sizes in either the 31-bit\n`size_` member of the `struct object_entry` or, when the value does not\nfit, the `pack->delta_size[]` spill array.  The accessors (`oe_size`,\n`oe_delta_size`, `oe_get_size_slow`, `oe_size_*_than`) and the setters\n(`oe_set_size`, `oe_set_delta_size`) used `unsigned long` for the spill\ntype, which on Windows means the spill silently caps at 4 GiB per entry.\nThat is what made `upload-pack` die with \"object too large to read on\nthis platform\" when serving the >4 GiB blob in `t5608` tests 5 and 6\nwhen run with `GIT_TEST_CLONE_2GB`.\n\nWiden them all to `size_t` (including `pack->delta_size`) and drop the\nthree `cast_size_t_to_ulong()` calls in `check_object()` that guarded\n`in_pack_size`.  The two `SET_SIZE(entry, canonical_size)` calls in the\nsame function stay cast-free as before, since `canonical_size` is still\n`unsigned long` until a later commit widens `object_info::sizep`.\n\nAssisted-by: Opus 4.7\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n builtin/pack-objects.c | 35 ++++++++++++++++++-----------------\n pack-objects.h         |  2 +-\n 2 files changed, 19 insertions(+), 18 deletions(-)\n\ndiff --git a/builtin/pack-objects.c b/builtin/pack-objects.c\nindex 975f04d699..bb372d0b03 100644\n--- a/builtin/pack-objects.c\n+++ b/builtin/pack-objects.c\n@@ -66,8 +66,8 @@ static inline struct object_entry *oe_delta(\n \t\treturn &pack->objects[e->delta_idx - 1];\n }\n \n-static inline unsigned long oe_delta_size(struct packing_data *pack,\n-\t\t\t\t\t  const struct object_entry *e)\n+static inline size_t oe_delta_size(struct packing_data *pack,\n+\t\t\t\t   const struct object_entry *e)\n {\n \tif (e->delta_size_valid)\n \t\treturn e->delta_size_;\n@@ -83,11 +83,11 @@ static inline unsigned long oe_delta_size(struct packing_data *pack,\n \treturn pack->delta_size[e - pack->objects];\n }\n \n-unsigned long oe_get_size_slow(struct packing_data *pack,\n-\t\t\t       const struct object_entry *e);\n+size_t oe_get_size_slow(struct packing_data *pack,\n+\t\t\tconst struct object_entry *e);\n \n-static inline unsigned long oe_size(struct packing_data *pack,\n-\t\t\t\t    const struct object_entry *e)\n+static inline size_t oe_size(struct packing_data *pack,\n+\t\t\t     const struct object_entry *e)\n {\n \tif (e->size_valid)\n \t\treturn e->size_;\n@@ -145,7 +145,7 @@ static inline void oe_set_delta_sibling(struct packing_data *pack,\n \n static inline void oe_set_size(struct packing_data *pack,\n \t\t\t       struct object_entry *e,\n-\t\t\t       unsigned long size)\n+\t\t\t       size_t size)\n {\n \tif (size < pack->oe_size_limit) {\n \t\te->size_ = size;\n@@ -159,7 +159,7 @@ static inline void oe_set_size(struct packing_data *pack,\n \n static inline void oe_set_delta_size(struct packing_data *pack,\n \t\t\t\t     struct object_entry *e,\n-\t\t\t\t     unsigned long size)\n+\t\t\t\t     size_t size)\n {\n \tif (size < pack->oe_delta_size_limit) {\n \t\te->delta_size_ = size;\n@@ -496,7 +496,7 @@ static void copy_pack_data(struct hashfile *f,\n \n static inline int oe_size_greater_than(struct packing_data *pack,\n \t\t\t\t       const struct object_entry *lhs,\n-\t\t\t\t       unsigned long rhs)\n+\t\t\t\t       size_t rhs)\n {\n \tif (lhs->size_valid)\n \t\treturn lhs->size_ > rhs;\n@@ -2277,7 +2277,7 @@ static void check_object(struct object_entry *entry, uint32_t object_index)\n \t\tdefault:\n \t\t\t/* Not a delta hence we've already got all we need. */\n \t\t\toe_set_type(entry, entry->in_pack_type);\n-\t\t\tSET_SIZE(entry, cast_size_t_to_ulong(in_pack_size));\n+\t\t\tSET_SIZE(entry, in_pack_size);\n \t\t\tentry->in_pack_header_size = used;\n \t\t\tif (oe_type(entry) < OBJ_COMMIT || oe_type(entry) > OBJ_BLOB)\n \t\t\t\tgoto give_up;\n@@ -2331,8 +2331,8 @@ static void check_object(struct object_entry *entry, uint32_t object_index)\n \t\tif (have_base &&\n \t\t    can_reuse_delta(&base_ref, entry, &base_entry)) {\n \t\t\toe_set_type(entry, entry->in_pack_type);\n-\t\t\tSET_SIZE(entry, cast_size_t_to_ulong(in_pack_size)); /* delta size */\n-\t\t\tSET_DELTA_SIZE(entry, cast_size_t_to_ulong(in_pack_size));\n+\t\t\tSET_SIZE(entry, in_pack_size); /* delta size */\n+\t\t\tSET_DELTA_SIZE(entry, in_pack_size);\n \n \t\t\tif (base_entry) {\n \t\t\t\tSET_DELTA(entry, base_entry);\n@@ -2355,7 +2355,8 @@ static void check_object(struct object_entry *entry, uint32_t object_index)\n \t\t\t * object size from the delta header.\n \t\t\t */\n \t\t\tdelta_pos = entry->in_pack_offset + entry->in_pack_header_size;\n-\t\t\tcanonical_size = get_size_from_delta(p, &w_curs, delta_pos);\n+\t\t\tcanonical_size = get_size_from_delta(p, &w_curs,\n+\t\t\t\t\t\t\t     delta_pos);\n \t\t\tif (canonical_size == 0)\n \t\t\t\tgoto give_up;\n \t\t\tSET_SIZE(entry, canonical_size);\n@@ -2711,7 +2712,7 @@ static pthread_mutex_t progress_mutex;\n \n static inline int oe_size_less_than(struct packing_data *pack,\n \t\t\t\t    const struct object_entry *lhs,\n-\t\t\t\t    unsigned long rhs)\n+\t\t\t\t    size_t rhs)\n {\n \tif (lhs->size_valid)\n \t\treturn lhs->size_ < rhs;\n@@ -2734,8 +2735,8 @@ static inline void oe_set_tree_depth(struct packing_data *pack,\n  * reconstruction (so non-deltas are true object sizes, but deltas\n  * return the size of the delta data).\n  */\n-unsigned long oe_get_size_slow(struct packing_data *pack,\n-\t\t\t       const struct object_entry *e)\n+size_t oe_get_size_slow(struct packing_data *pack,\n+\t\t\tconst struct object_entry *e)\n {\n \tstruct packed_git *p;\n \tstruct pack_window *w_curs;\n@@ -2769,7 +2770,7 @@ unsigned long oe_get_size_slow(struct packing_data *pack,\n \n \tunuse_pack(&w_curs);\n \tpacking_data_unlock(&to_pack);\n-\treturn cast_size_t_to_ulong(size);\n+\treturn size;\n }\n \n static int try_delta(struct unpacked *trg, struct unpacked *src,\ndiff --git a/pack-objects.h b/pack-objects.h\nindex 83299d4732..e97e84ddcb 100644\n--- a/pack-objects.h\n+++ b/pack-objects.h\n@@ -141,7 +141,7 @@ struct packing_data {\n \tuint32_t index_size;\n \n \tunsigned int *in_pack_pos;\n-\tunsigned long *delta_size;\n+\tsize_t *delta_size;\n \n \t/*\n \t * Only one of these can be non-NULL and they have different\n-- \ngitgitgadget\n\n"},{"id":"544722","messageId":"460d733feeaf2a94fe28d7509cc4128e9c0a7610.1780570273.git.gitgitgadget@gmail.com","threadId":"65750","inReplyTo":"pull.2137.git.1780570272.gitgitgadget@gmail.com","subject":"[PATCH 6/7] packfile,delta: drop the `cast_size_t_to_ulong()` wrappers","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2026-06-04T10:51:11Z","receivedAt":"2026-06-04T10:51:27Z","isPatch":true,"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nWhen I started the transition from `unsigned long` to `size_t`, in the\ninterest of keeping the patches reviewable, I introduced these calls to\nprevent data type narrowing from silently failing to handle large object\nsizes. I also introduced `*_sz()` variants that would allow most of the\ncallers to keep using that `unsigned long` that the 90s kindly asked to\nbe returned.\n\nAfter the preceding commits, the only places that called the narrow\nwrappers either no longer exist or already use the `_sz` form\ninternally, so the wrappers just narrow values back through\n`cast_size_t_to_ulong()` for no reason.\n\nDrop them and rename the `_sz` variants back to the natural names.\n\nAssisted-by: Opus 4.7\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n delta.h       | 14 ++------------\n packfile.c    | 28 ++++++++--------------------\n packfile.h    |  2 +-\n patch-delta.c |  4 ++--\n 4 files changed, 13 insertions(+), 35 deletions(-)\n\ndiff --git a/delta.h b/delta.h\nindex bb149dc82b..eb5c6d2fdb 100644\n--- a/delta.h\n+++ b/delta.h\n@@ -86,11 +86,8 @@ void *patch_delta(const void *src_buf, size_t src_size,\n  * This must be called twice on the delta data buffer, first to get the\n  * expected source buffer size, and again to get the target buffer size.\n  */\n-/*\n- * Size_t variant that doesn't truncate - use for >4GB objects on Windows.\n- */\n-static inline size_t get_delta_hdr_size_sz(const unsigned char **datap,\n-\t\t\t\t\t   const unsigned char *top)\n+static inline size_t get_delta_hdr_size(const unsigned char **datap,\n+\t\t\t\t\tconst unsigned char *top)\n {\n \tconst unsigned char *data = *datap;\n \tsize_t cmd, size = 0;\n@@ -104,11 +101,4 @@ static inline size_t get_delta_hdr_size_sz(const unsigned char **datap,\n \treturn size;\n }\n \n-static inline unsigned long get_delta_hdr_size(const unsigned char **datap,\n-\t\t\t\t\t       const unsigned char *top)\n-{\n-\tsize_t size = get_delta_hdr_size_sz(datap, top);\n-\treturn cast_size_t_to_ulong(size);\n-}\n-\n #endif\ndiff --git a/packfile.c b/packfile.c\nindex dab0a9b16d..c174982d10 100644\n--- a/packfile.c\n+++ b/packfile.c\n@@ -1164,11 +1164,12 @@ unsigned long unpack_object_header_buffer(const unsigned char *buf,\n }\n \n /*\n- * Size_t variant for >4GB delta results on Windows.\n+ * Read a delta object's header at curpos in p (already inflated as needed)\n+ * and return the size of the result object (the post-application target).\n  */\n-static size_t get_size_from_delta_sz(struct packed_git *p,\n-\t\t\t\t     struct pack_window **w_curs,\n-\t\t\t\t     off_t curpos)\n+size_t get_size_from_delta(struct packed_git *p,\n+\t\t\t   struct pack_window **w_curs,\n+\t\t\t   off_t curpos)\n {\n \tconst unsigned char *data;\n \tunsigned char delta_head[20], *in;\n@@ -1215,18 +1216,10 @@ static size_t get_size_from_delta_sz(struct packed_git *p,\n \tdata = delta_head;\n \n \t/* ignore base size */\n-\tget_delta_hdr_size_sz(&data, delta_head+sizeof(delta_head));\n+\tget_delta_hdr_size(&data, delta_head+sizeof(delta_head));\n \n \t/* Read the result size */\n-\treturn get_delta_hdr_size_sz(&data, delta_head+sizeof(delta_head));\n-}\n-\n-unsigned long get_size_from_delta(struct packed_git *p,\n-\t\t\t\t  struct pack_window **w_curs,\n-\t\t\t\t  off_t curpos)\n-{\n-\tsize_t size = get_size_from_delta_sz(p, w_curs, curpos);\n-\treturn cast_size_t_to_ulong(size);\n+\treturn get_delta_hdr_size(&data, delta_head+sizeof(delta_head));\n }\n \n int unpack_object_header(struct packed_git *p,\n@@ -1634,12 +1627,7 @@ static int packed_object_info_with_index_pos(struct packed_git *p, off_t obj_off\n \t\t\t\tret = -1;\n \t\t\t\tgoto out;\n \t\t\t}\n-\t\t\t/*\n-\t\t\t * Use size_t variant to avoid die() on >4GB deltas.\n-\t\t\t * oi->sizep is unsigned long, so truncation may occur,\n-\t\t\t * but streaming code uses its own size_t tracking.\n-\t\t\t */\n-\t\t\tsize = get_size_from_delta_sz(p, &w_curs, tmp_pos);\n+\t\t\tsize = get_size_from_delta(p, &w_curs, tmp_pos);\n \t\t\tif (size == 0) {\n \t\t\t\tret = -1;\n \t\t\t\tgoto out;\ndiff --git a/packfile.h b/packfile.h\nindex 0b5ae3f9fc..bd4494906d 100644\n--- a/packfile.h\n+++ b/packfile.h\n@@ -458,7 +458,7 @@ int is_pack_valid(struct packed_git *);\n void *unpack_entry(struct repository *r, struct packed_git *, off_t,\n \t\t   enum object_type *, size_t *);\n unsigned long unpack_object_header_buffer(const unsigned char *buf, unsigned long len, enum object_type *type, size_t *sizep);\n-unsigned long get_size_from_delta(struct packed_git *, struct pack_window **, off_t);\n+size_t get_size_from_delta(struct packed_git *, struct pack_window **, off_t);\n int unpack_object_header(struct packed_git *, struct pack_window **, off_t *, size_t *);\n off_t get_delta_base(struct packed_git *p, struct pack_window **w_curs,\n \t\t     off_t *curpos, enum object_type type,\ndiff --git a/patch-delta.c b/patch-delta.c\nindex 44cda97994..42199fa956 100644\n--- a/patch-delta.c\n+++ b/patch-delta.c\n@@ -27,12 +27,12 @@ void *patch_delta(const void *src_buf, size_t src_size,\n \ttop = (const unsigned char *) delta_buf + delta_size;\n \n \t/* make sure the orig file size matches what we expect */\n-\tsize = get_delta_hdr_size_sz(&data, top);\n+\tsize = get_delta_hdr_size(&data, top);\n \tif (size != src_size)\n \t\treturn NULL;\n \n \t/* now the result size */\n-\tsize = get_delta_hdr_size_sz(&data, top);\n+\tsize = get_delta_hdr_size(&data, top);\n \tdst_buf = xmallocz(size);\n \n \tout = dst_buf;\n-- \ngitgitgadget\n\n"},{"id":"544723","messageId":"f3aeae983ac8b281d6ba54299961e19d16699c94.1780570273.git.gitgitgadget@gmail.com","threadId":"65750","inReplyTo":"pull.2137.git.1780570272.gitgitgadget@gmail.com","subject":"[PATCH 7/7] odb: use size_t for object_info.sizep and the size APIs","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2026-06-04T10:51:12Z","receivedAt":"2026-06-04T10:51:30Z","isPatch":true,"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nWhen `js/objects-larger-than-4gb-on-windows` widened the streaming,\nindex-pack and unpack-objects code paths, in the interest of keeping the\npatches somewhat reasonably-sized, it left the public ODB API still\ntyped in `unsigned long`. In particular `struct object_info::sizep` and\nthe four wrappers built on top of it (`odb_read_object`,\n`odb_read_object_peeled`, `odb_read_object_info`, `odb_pretend_object`)\nstill return the unpacked size through `unsigned long *`, so on Windows\n`cat-file -s` and the `git add` / `git status` paths for a >4 GiB blob\nsilently cap at 4 GiB.\n\nWiden the field and the four wrappers. The previous commits already\nwidened the `unpack_entry()` cascade and pack-objects' in-core size\naccessors, so most of the cascade arrives here with no further work: the\ntemporary shims in `packed_object_info_with_index_pos()` and in\n`unpack_entry()`'s delta-base recovery path go away, the two\n`SET_SIZE(entry, cast_size_t_to_ulong(canonical_size))` calls in\n`check_object()` and the matching one in `drop_reused_delta()` collapse\nto plain `SET_SIZE`, and `oe_get_size_slow()`'s tail\n`cast_size_t_to_ulong()` is gone too.\n\nWhat remains narrow are the boundaries this series does not\nintend to touch: the diff, blame, textconv and fast-import machinery.\n\nEven so, this patch is unfortunately quite large.\n\nAssisted-by: Opus 4.7\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n apply.c                       |  6 +++---\n archive.c                     |  4 ++--\n attr.c                        |  2 +-\n bisect.c                      |  2 +-\n blame.c                       | 15 ++++++++++----\n builtin/cat-file.c            | 39 +++++++++++++++++++++--------------\n builtin/difftool.c            |  2 +-\n builtin/fast-export.c         |  7 +++++--\n builtin/fast-import.c         | 22 ++++++++++++++------\n builtin/fsck.c                |  2 +-\n builtin/grep.c                | 12 +++++------\n builtin/index-pack.c          |  6 +++---\n builtin/log.c                 |  2 +-\n builtin/ls-files.c            |  2 +-\n builtin/ls-tree.c             |  4 ++--\n builtin/merge-tree.c          |  6 +++---\n builtin/mktag.c               |  2 +-\n builtin/notes.c               |  6 +++---\n builtin/pack-objects.c        | 33 ++++++++++++++++++++---------\n builtin/repo.c                |  4 +++-\n builtin/tag.c                 |  4 ++--\n builtin/unpack-file.c         |  2 +-\n builtin/unpack-objects.c      |  6 ++++--\n bundle.c                      |  2 +-\n combine-diff.c                |  4 +++-\n commit.c                      | 10 ++++-----\n config.c                      |  2 +-\n diff.c                        |  5 ++++-\n dir.c                         |  2 +-\n entry.c                       |  4 +---\n fmt-merge-msg.c               |  4 ++--\n fsck.c                        |  2 +-\n grep.c                        |  4 +++-\n http-push.c                   |  2 +-\n list-objects-filter.c         |  2 +-\n mailmap.c                     |  2 +-\n match-trees.c                 |  4 ++--\n merge-blobs.c                 |  6 +++---\n merge-blobs.h                 |  2 +-\n merge-ort.c                   |  2 +-\n notes-cache.c                 |  2 +-\n notes-merge.c                 |  2 +-\n notes.c                       |  8 ++++---\n object-file.c                 | 18 +++++-----------\n object.c                      |  2 +-\n odb.c                         | 12 +++++------\n odb.h                         | 10 ++++-----\n odb/streaming.c               | 13 +-----------\n pack-bitmap.c                 |  4 ++--\n packfile.c                    | 12 +++--------\n path-walk.c                   |  2 +-\n protocol-caps.c               |  5 +++--\n read-cache.c                  |  6 +++---\n ref-filter.c                  |  2 +-\n reflog.c                      |  2 +-\n rerere.c                      |  2 +-\n submodule-config.c            |  2 +-\n t/helper/test-pack-deltas.c   |  3 ++-\n t/helper/test-partial-clone.c |  2 +-\n t/unit-tests/u-odb-inmemory.c |  2 +-\n tag.c                         |  4 ++--\n tree-walk.c                   | 10 +++++----\n tree.c                        |  2 +-\n xdiff-interface.c             |  2 +-\n 64 files changed, 205 insertions(+), 173 deletions(-)\n\ndiff --git a/apply.c b/apply.c\nindex 3cf544e9a9..5e54453f79 100644\n--- a/apply.c\n+++ b/apply.c\n@@ -3321,7 +3321,7 @@ static int apply_binary(struct apply_state *state,\n \tif (odb_has_object(the_repository->objects, &oid, 0)) {\n \t\t/* We already have the postimage */\n \t\tenum object_type type;\n-\t\tunsigned long size;\n+\t\tsize_t size;\n \t\tchar *result;\n \n \t\tresult = odb_read_object(the_repository->objects, &oid,\n@@ -3384,7 +3384,7 @@ static int read_blob_object(struct strbuf *buf, const struct object_id *oid, uns\n \t\tstrbuf_addf(buf, \"Subproject commit %s\\n\", oid_to_hex(oid));\n \t} else {\n \t\tenum object_type type;\n-\t\tunsigned long sz;\n+\t\tsize_t sz;\n \t\tchar *result;\n \n \t\tresult = odb_read_object(the_repository->objects, oid,\n@@ -3611,7 +3611,7 @@ static int load_preimage(struct apply_state *state,\n \n static int resolve_to(struct image *image, const struct object_id *result_id)\n {\n-\tunsigned long size;\n+\tsize_t size;\n \tenum object_type type;\n \tchar *data;\n \ndiff --git a/archive.c b/archive.c\nindex 51229107a5..59790be986 100644\n--- a/archive.c\n+++ b/archive.c\n@@ -87,7 +87,7 @@ static void *object_file_to_archive(const struct archiver_args *args,\n \t\t\t\t    const struct object_id *oid,\n \t\t\t\t    unsigned int mode,\n \t\t\t\t    enum object_type *type,\n-\t\t\t\t    unsigned long *sizep)\n+\t\t\t\t    size_t *sizep)\n {\n \tvoid *buffer;\n \tconst struct commit *commit = args->convert ? args->commit : NULL;\n@@ -158,7 +158,7 @@ static int write_archive_entry(const struct object_id *oid, const char *base,\n \twrite_archive_entry_fn_t write_entry = c->write_entry;\n \tint err;\n \tconst char *path_without_prefix;\n-\tunsigned long size;\n+\tsize_t size;\n \tvoid *buffer;\n \tenum object_type type;\n \ndiff --git a/attr.c b/attr.c\nindex 75369547b3..c61472a4e6 100644\n--- a/attr.c\n+++ b/attr.c\n@@ -768,7 +768,7 @@ static struct attr_stack *read_attr_from_blob(struct index_state *istate,\n \t\t\t\t\t      const char *path, unsigned flags)\n {\n \tstruct object_id oid;\n-\tunsigned long sz;\n+\tsize_t sz;\n \tenum object_type type;\n \tvoid *buf;\n \tunsigned short mode;\ndiff --git a/bisect.c b/bisect.c\nindex 905a9afb05..4742a5fef4 100644\n--- a/bisect.c\n+++ b/bisect.c\n@@ -154,7 +154,7 @@ static void show_list(const char *debug, int counted, int nr,\n \t\tstruct commit *commit = p->item;\n \t\tunsigned commit_flags = commit->object.flags;\n \t\tenum object_type type;\n-\t\tunsigned long size;\n+\t\tsize_t size;\n \t\tchar *buf = odb_read_object(the_repository->objects,\n \t\t\t\t\t    &commit->object.oid, &type,\n \t\t\t\t\t    &size);\ndiff --git a/blame.c b/blame.c\nindex 977cbb7097..126e232416 100644\n--- a/blame.c\n+++ b/blame.c\n@@ -1041,10 +1041,13 @@ static void fill_origin_blob(struct diff_options *opt,\n \t\t    textconv_object(opt->repo, o->path, o->mode,\n \t\t\t\t    &o->blob_oid, 1, &file->ptr, &file_size))\n \t\t\t;\n-\t\telse\n+\t\telse {\n+\t\t\tsize_t file_size_st = 0;\n \t\t\tfile->ptr = odb_read_object(the_repository->objects,\n \t\t\t\t\t\t    &o->blob_oid, &type,\n-\t\t\t\t\t\t    &file_size);\n+\t\t\t\t\t\t    &file_size_st);\n+\t\t\tfile_size = cast_size_t_to_ulong(file_size_st);\n+\t\t}\n \t\tfile->size = file_size;\n \n \t\tif (!file->ptr)\n@@ -2869,10 +2872,14 @@ void setup_scoreboard(struct blame_scoreboard *sb,\n \t\t    textconv_object(sb->repo, sb->path, o->mode, &o->blob_oid, 1, (char **) &sb->final_buf,\n \t\t\t\t    &sb->final_buf_size))\n \t\t\t;\n-\t\telse\n+\t\telse {\n+\t\t\tsize_t final_buf_size_st = 0;\n \t\t\tsb->final_buf = odb_read_object(the_repository->objects,\n \t\t\t\t\t\t\t&o->blob_oid, &type,\n-\t\t\t\t\t\t\t&sb->final_buf_size);\n+\t\t\t\t\t\t\t&final_buf_size_st);\n+\t\t\tsb->final_buf_size =\n+\t\t\t\tcast_size_t_to_ulong(final_buf_size_st);\n+\t\t}\n \n \t\tif (!sb->final_buf)\n \t\t\tdie(_(\"cannot read blob %s for path %s\"),\ndiff --git a/builtin/cat-file.c b/builtin/cat-file.c\nindex fa45f774d7..fa6e396ddc 100644\n--- a/builtin/cat-file.c\n+++ b/builtin/cat-file.c\n@@ -84,7 +84,7 @@ static char *replace_idents_using_mailmap(char *object_buf, size_t *size)\n \n static int filter_object(const char *path, unsigned mode,\n \t\t\t const struct object_id *oid,\n-\t\t\t char **buf, unsigned long *size)\n+\t\t\t char **buf, size_t *size)\n {\n \tenum object_type type;\n \n@@ -120,7 +120,7 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name)\n \tstruct object_id oid;\n \tenum object_type type;\n \tchar *buf;\n-\tunsigned long size;\n+\tsize_t size;\n \tstruct object_context obj_context = {0};\n \tstruct object_info oi = OBJECT_INFO_INIT;\n \tunsigned flags = OBJECT_INFO_LOOKUP_REPLACE;\n@@ -166,7 +166,7 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name)\n \t\tif (use_mailmap && (type == OBJ_COMMIT || type == OBJ_TAG)) {\n \t\t\tsize_t s = size;\n \t\t\tbuf = replace_idents_using_mailmap(buf, &s);\n-\t\t\tsize = cast_size_t_to_ulong(s);\n+\t\t\tsize = s;\n \t\t}\n \n \t\tprintf(\"%\"PRIuMAX\"\\n\", (uintmax_t)size);\n@@ -188,9 +188,15 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name)\n \t\tbreak;\n \n \tcase 'c':\n-\t\tif (textconv_object(the_repository, path, obj_context.mode,\n-\t\t\t\t    &oid, 1, &buf, &size))\n+\t{\n+\t\tunsigned long size_ul = 0;\n+\t\tint textconv_ret = textconv_object(the_repository, path,\n+\t\t\t\t\t\t   obj_context.mode, &oid, 1,\n+\t\t\t\t\t\t   &buf, &size_ul);\n+\t\tsize = size_ul;\n+\t\tif (textconv_ret)\n \t\t\tbreak;\n+\t}\n \t\t/* else fallthrough */\n \n \tcase 'p':\n@@ -219,7 +225,7 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name)\n \t\tif (use_mailmap) {\n \t\t\tsize_t s = size;\n \t\t\tbuf = replace_idents_using_mailmap(buf, &s);\n-\t\t\tsize = cast_size_t_to_ulong(s);\n+\t\t\tsize = s;\n \t\t}\n \n \t\t/* otherwise just spit out the data */\n@@ -266,7 +272,7 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name)\n \t\tif (use_mailmap) {\n \t\t\tsize_t s = size;\n \t\t\tbuf = replace_idents_using_mailmap(buf, &s);\n-\t\t\tsize = cast_size_t_to_ulong(s);\n+\t\t\tsize = s;\n \t\t}\n \t\tbreak;\n \t}\n@@ -288,7 +294,7 @@ cleanup:\n struct expand_data {\n \tstruct object_id oid;\n \tenum object_type type;\n-\tunsigned long size;\n+\tsize_t size;\n \tunsigned short mode;\n \toff_t disk_size;\n \tconst char *rest;\n@@ -405,7 +411,7 @@ static void print_object_or_die(struct batch_options *opt, struct expand_data *d\n \t\t\tfflush(stdout);\n \t\tif (opt->transform_mode) {\n \t\t\tchar *contents;\n-\t\t\tunsigned long size;\n+\t\t\tsize_t size;\n \n \t\t\tif (!data->rest)\n \t\t\t\tdie(\"missing path for '%s'\", oid_to_hex(oid));\n@@ -417,9 +423,12 @@ static void print_object_or_die(struct batch_options *opt, struct expand_data *d\n \t\t\t\t\t    oid_to_hex(oid), data->rest);\n \t\t\t} else if (opt->transform_mode == 'c') {\n \t\t\t\tenum object_type type;\n-\t\t\t\tif (!textconv_object(the_repository,\n-\t\t\t\t\t\t     data->rest, 0100644, oid,\n-\t\t\t\t\t\t     1, &contents, &size))\n+\t\t\t\tunsigned long size_ul = 0;\n+\t\t\t\tif (textconv_object(the_repository,\n+\t\t\t\t\t\t    data->rest, 0100644, oid,\n+\t\t\t\t\t\t    1, &contents, &size_ul))\n+\t\t\t\t\tsize = size_ul;\n+\t\t\t\telse\n \t\t\t\t\tcontents = odb_read_object(the_repository->objects,\n \t\t\t\t\t\t\t\t   oid, &type, &size);\n \t\t\t\tif (!contents)\n@@ -435,7 +444,7 @@ static void print_object_or_die(struct batch_options *opt, struct expand_data *d\n \t}\n \telse {\n \t\tenum object_type type;\n-\t\tunsigned long size;\n+\t\tsize_t size;\n \t\tvoid *contents;\n \n \t\tcontents = odb_read_object(the_repository->objects, oid,\n@@ -446,7 +455,7 @@ static void print_object_or_die(struct batch_options *opt, struct expand_data *d\n \t\tif (use_mailmap) {\n \t\t\tsize_t s = size;\n \t\t\tcontents = replace_idents_using_mailmap(contents, &s);\n-\t\t\tsize = cast_size_t_to_ulong(s);\n+\t\t\tsize = s;\n \t\t}\n \n \t\tif (type != data->type)\n@@ -555,7 +564,7 @@ static void batch_object_write(const char *obj_name,\n \t\t\tif (!buf)\n \t\t\t\tdie(_(\"unable to read %s\"), oid_to_hex(&data->oid));\n \t\t\tbuf = replace_idents_using_mailmap(buf, &s);\n-\t\t\tdata->size = cast_size_t_to_ulong(s);\n+\t\t\tdata->size = s;\n \n \t\t\tfree(buf);\n \t\t}\ndiff --git a/builtin/difftool.c b/builtin/difftool.c\nindex 2a21005f2e..26778f8515 100644\n--- a/builtin/difftool.c\n+++ b/builtin/difftool.c\n@@ -319,7 +319,7 @@ static char *get_symlink(struct repository *repo,\n \t\tdata = strbuf_detach(&link, NULL);\n \t} else {\n \t\tenum object_type type;\n-\t\tunsigned long size;\n+\t\tsize_t size;\n \t\tdata = odb_read_object(repo->objects, oid, &type, &size);\n \t\tif (!data)\n \t\t\tdie(_(\"could not read object %s for symlink %s\"),\ndiff --git a/builtin/fast-export.c b/builtin/fast-export.c\nindex 2eb43a28da..0be43104dc 100644\n--- a/builtin/fast-export.c\n+++ b/builtin/fast-export.c\n@@ -317,7 +317,10 @@ static void export_blob(const struct object_id *oid)\n \t\tobject = (struct object *)lookup_blob(the_repository, oid);\n \t\teaten = 0;\n \t} else {\n-\t\tbuf = odb_read_object(the_repository->objects, oid, &type, &size);\n+\t\tsize_t size_st = 0;\n+\t\tbuf = odb_read_object(the_repository->objects, oid, &type,\n+\t\t\t\t      &size_st);\n+\t\tsize = cast_size_t_to_ulong(size_st);\n \t\tif (!buf)\n \t\t\tdie(_(\"could not read blob %s\"), oid_to_hex(oid));\n \t\tif (check_object_signature(the_repository, oid, buf, size,\n@@ -880,7 +883,7 @@ static char *anonymize_tag(void)\n \n static void handle_tag(const char *name, struct tag *tag)\n {\n-\tunsigned long size;\n+\tsize_t size;\n \tenum object_type type;\n \tchar *buf;\n \tconst char *tagger, *tagger_end, *message;\ndiff --git a/builtin/fast-import.c b/builtin/fast-import.c\nindex 3dff898c43..d11a2cc2c1 100644\n--- a/builtin/fast-import.c\n+++ b/builtin/fast-import.c\n@@ -1291,7 +1291,10 @@ static void load_tree(struct tree_entry *root)\n \t\t\tdie(_(\"can't load tree %s\"), oid_to_hex(oid));\n \t} else {\n \t\tenum object_type type;\n-\t\tbuf = odb_read_object(the_repository->objects, oid, &type, &size);\n+\t\tsize_t size_st = 0;\n+\t\tbuf = odb_read_object(the_repository->objects, oid, &type,\n+\t\t\t\t      &size_st);\n+\t\tsize = cast_size_t_to_ulong(size_st);\n \t\tif (!buf || type != OBJ_TREE)\n \t\t\tdie(_(\"can't load tree %s\"), oid_to_hex(oid));\n \t}\n@@ -2560,7 +2563,7 @@ static void note_change_n(const char *p, struct branch *b, unsigned char *old_fa\n \t\t\tdie(_(\"mark :%\" PRIuMAX \" not a commit\"), commit_mark);\n \t\toidcpy(&commit_oid, &commit_oe->idx.oid);\n \t} else if (!repo_get_oid(the_repository, p, &commit_oid)) {\n-\t\tunsigned long size;\n+\t\tsize_t size;\n \t\tchar *buf = odb_read_object_peeled(the_repository->objects,\n \t\t\t\t\t\t   &commit_oid, OBJ_COMMIT, &size,\n \t\t\t\t\t\t   &commit_oid);\n@@ -2627,10 +2630,12 @@ static void parse_from_existing(struct branch *b)\n \t\toidclr(&b->branch_tree.versions[1].oid, the_repository->hash_algo);\n \t} else {\n \t\tunsigned long size;\n+\t\tsize_t size_st = 0;\n \t\tchar *buf;\n \n \t\tbuf = odb_read_object_peeled(the_repository->objects, &b->oid,\n-\t\t\t\t\t     OBJ_COMMIT, &size, &b->oid);\n+\t\t\t\t\t     OBJ_COMMIT, &size_st, &b->oid);\n+\t\tsize = cast_size_t_to_ulong(size_st);\n \t\tparse_from_commit(b, buf, size);\n \t\tfree(buf);\n \t}\n@@ -2722,7 +2727,7 @@ static struct hash_list *parse_merge(unsigned int *count)\n \t\t\t\tdie(_(\"mark :%\" PRIuMAX \" not a commit\"), idnum);\n \t\t\toidcpy(&n->oid, &oe->idx.oid);\n \t\t} else if (!repo_get_oid(the_repository, from, &n->oid)) {\n-\t\t\tunsigned long size;\n+\t\t\tsize_t size;\n \t\t\tchar *buf = odb_read_object_peeled(the_repository->objects,\n \t\t\t\t\t\t\t   &n->oid, OBJ_COMMIT,\n \t\t\t\t\t\t\t   &size, &n->oid);\n@@ -3330,7 +3335,10 @@ static void cat_blob(struct object_entry *oe, struct object_id *oid)\n \tchar *buf;\n \n \tif (!oe || oe->pack_id == MAX_PACK_ID) {\n-\t\tbuf = odb_read_object(the_repository->objects, oid, &type, &size);\n+\t\tsize_t size_st = 0;\n+\t\tbuf = odb_read_object(the_repository->objects, oid, &type,\n+\t\t\t\t      &size_st);\n+\t\tsize = cast_size_t_to_ulong(size_st);\n \t} else {\n \t\ttype = oe->type;\n \t\tbuf = gfi_unpack_entry(oe, &size);\n@@ -3438,8 +3446,10 @@ static struct object_entry *dereference(struct object_entry *oe,\n \t\tbuf = gfi_unpack_entry(oe, &size);\n \t} else {\n \t\tenum object_type unused;\n+\t\tsize_t size_st = 0;\n \t\tbuf = odb_read_object(the_repository->objects, oid,\n-\t\t\t\t      &unused, &size);\n+\t\t\t\t      &unused, &size_st);\n+\t\tsize = cast_size_t_to_ulong(size_st);\n \t}\n \tif (!buf)\n \t\tdie(_(\"can't load object %s\"), oid_to_hex(oid));\ndiff --git a/builtin/fsck.c b/builtin/fsck.c\nindex 248f8ff5a0..76b723f36d 100644\n--- a/builtin/fsck.c\n+++ b/builtin/fsck.c\n@@ -724,7 +724,7 @@ static int fsck_loose(const struct object_id *oid, const char *path,\n \tstruct for_each_loose_cb *data = cb_data;\n \tstruct object *obj;\n \tenum object_type type = OBJ_NONE;\n-\tunsigned long size;\n+\tsize_t size;\n \tvoid *contents = NULL;\n \tint eaten;\n \tstruct object_info oi = OBJECT_INFO_INIT;\ndiff --git a/builtin/grep.c b/builtin/grep.c\nindex 6a09571903..26b85479ca 100644\n--- a/builtin/grep.c\n+++ b/builtin/grep.c\n@@ -520,7 +520,7 @@ static int grep_submodule(struct grep_opt *opt,\n \t\tenum object_type object_type;\n \t\tstruct tree_desc tree;\n \t\tvoid *data;\n-\t\tunsigned long size;\n+\t\tsize_t size;\n \t\tstruct strbuf base = STRBUF_INIT;\n \n \t\tobj_read_lock();\n@@ -573,7 +573,7 @@ static int grep_cache(struct grep_opt *opt,\n \t\t\tenum object_type type;\n \t\t\tstruct tree_desc tree;\n \t\t\tvoid *data;\n-\t\t\tunsigned long size;\n+\t\t\tsize_t size;\n \n \t\t\tdata = odb_read_object(the_repository->objects, &ce->oid,\n \t\t\t\t\t       &type, &size);\n@@ -666,7 +666,7 @@ static int grep_tree(struct grep_opt *opt, const struct pathspec *pathspec,\n \t\t\tenum object_type type;\n \t\t\tstruct tree_desc sub;\n \t\t\tvoid *data;\n-\t\t\tunsigned long size;\n+\t\t\tsize_t size;\n \n \t\t\tdata = odb_read_object(the_repository->objects,\n \t\t\t\t\t       &entry.oid, &type, &size);\n@@ -730,7 +730,7 @@ static void collect_blob_oids_for_tree(struct repository *repo,\n \t\t\tenum object_type type;\n \t\t\tstruct tree_desc sub_tree;\n \t\t\tvoid *data;\n-\t\t\tunsigned long size;\n+\t\t\tsize_t size;\n \n \t\t\tdata = odb_read_object(repo->objects, &entry.oid,\n \t\t\t\t\t       &type, &size);\n@@ -764,7 +764,7 @@ static void collect_blob_oids_for_treeish(struct grep_opt *opt,\n {\n \tstruct tree_desc tree;\n \tvoid *data;\n-\tunsigned long size;\n+\tsize_t size;\n \tstruct strbuf base = STRBUF_INIT;\n \tint len;\n \n@@ -841,7 +841,7 @@ static int grep_object(struct grep_opt *opt, const struct pathspec *pathspec,\n \tif (obj->type == OBJ_COMMIT || obj->type == OBJ_TREE) {\n \t\tstruct tree_desc tree;\n \t\tvoid *data;\n-\t\tunsigned long size;\n+\t\tsize_t size;\n \t\tstruct strbuf base;\n \t\tint hit, len;\n \ndiff --git a/builtin/index-pack.c b/builtin/index-pack.c\nindex 3c4474e681..78da3a6566 100644\n--- a/builtin/index-pack.c\n+++ b/builtin/index-pack.c\n@@ -258,7 +258,7 @@ static unsigned check_object(struct object *obj)\n \t\treturn 0;\n \n \tif (!(obj->flags & FLAG_CHECKED)) {\n-\t\tunsigned long size;\n+\t\tsize_t size;\n \t\tint type = odb_read_object_info(the_repository->objects,\n \t\t\t\t\t\t&obj->oid, &size);\n \t\tif (type <= 0)\n@@ -905,7 +905,7 @@ static void sha1_object(const void *data, struct object_entry *obj_entry,\n \tif (collision_test_needed) {\n \t\tvoid *has_data;\n \t\tenum object_type has_type;\n-\t\tunsigned long has_size;\n+\t\tsize_t has_size;\n \t\tread_lock();\n \t\thas_type = odb_read_object_info(the_repository->objects, oid, &has_size);\n \t\tif (has_type < 0)\n@@ -1515,7 +1515,7 @@ static void fix_unresolved_deltas(struct hashfile *f)\n \t\tstruct ref_delta_entry *d = sorted_by_pos[i];\n \t\tenum object_type type;\n \t\tvoid *data;\n-\t\tunsigned long size;\n+\t\tsize_t size;\n \n \t\tif (objects[d->obj_no].real_type != OBJ_REF_DELTA)\n \t\t\tcontinue;\ndiff --git a/builtin/log.c b/builtin/log.c\nindex e464b30af4..d027ce1e0b 100644\n--- a/builtin/log.c\n+++ b/builtin/log.c\n@@ -613,7 +613,7 @@ static int show_blob_object(const struct object_id *oid, struct rev_info *rev, c\n \n static int show_tag_object(const struct object_id *oid, struct rev_info *rev)\n {\n-\tunsigned long size;\n+\tsize_t size;\n \tenum object_type type;\n \tchar *buf = odb_read_object(the_repository->objects, oid, &type, &size);\n \tunsigned long offset = 0;\ndiff --git a/builtin/ls-files.c b/builtin/ls-files.c\nindex e1a22b41b9..bfbd145e97 100644\n--- a/builtin/ls-files.c\n+++ b/builtin/ls-files.c\n@@ -251,7 +251,7 @@ static void expand_objectsize(struct repository *repo, struct strbuf *line,\n \t\t\t      const enum object_type type, unsigned int padded)\n {\n \tif (type == OBJ_BLOB) {\n-\t\tunsigned long size;\n+\t\tsize_t size;\n \t\tif (odb_read_object_info(repo->objects, oid, &size) < 0)\n \t\t\tdie(_(\"could not get object info about '%s'\"),\n \t\t\t    oid_to_hex(oid));\ndiff --git a/builtin/ls-tree.c b/builtin/ls-tree.c\nindex 113e4a960d..7d075bfca2 100644\n--- a/builtin/ls-tree.c\n+++ b/builtin/ls-tree.c\n@@ -27,7 +27,7 @@ static void expand_objectsize(struct strbuf *line, const struct object_id *oid,\n \t\t\t      const enum object_type type, unsigned int padded)\n {\n \tif (type == OBJ_BLOB) {\n-\t\tunsigned long size;\n+\t\tsize_t size;\n \t\tif (odb_read_object_info(the_repository->objects, oid, &size) < 0)\n \t\t\tdie(_(\"could not get object info about '%s'\"),\n \t\t\t    oid_to_hex(oid));\n@@ -217,7 +217,7 @@ static int show_tree_long(const struct object_id *oid, struct strbuf *base,\n \t\treturn early;\n \n \tif (type == OBJ_BLOB) {\n-\t\tunsigned long size;\n+\t\tsize_t size;\n \t\tif (odb_read_object_info(the_repository->objects, oid, &size) == OBJ_BAD)\n \t\t\txsnprintf(size_text, sizeof(size_text), \"BAD\");\n \t\telse\ndiff --git a/builtin/merge-tree.c b/builtin/merge-tree.c\nindex 312b595d1e..49f41e520f 100644\n--- a/builtin/merge-tree.c\n+++ b/builtin/merge-tree.c\n@@ -69,7 +69,7 @@ static const char *explanation(struct merge_list *entry)\n \treturn \"removed in remote\";\n }\n \n-static void *result(struct merge_list *entry, unsigned long *size)\n+static void *result(struct merge_list *entry, size_t *size)\n {\n \tenum object_type type;\n \tstruct blob *base, *our, *their;\n@@ -96,7 +96,7 @@ static void *result(struct merge_list *entry, unsigned long *size)\n \t\t\t   base, our, their, size);\n }\n \n-static void *origin(struct merge_list *entry, unsigned long *size)\n+static void *origin(struct merge_list *entry, size_t *size)\n {\n \tenum object_type type;\n \twhile (entry) {\n@@ -119,7 +119,7 @@ static int show_outf(void *priv UNUSED, mmbuffer_t *mb, int nbuf)\n \n static void show_diff(struct merge_list *entry)\n {\n-\tunsigned long size;\n+\tsize_t size;\n \tmmfile_t src, dst;\n \txpparam_t xpp;\n \txdemitconf_t xecfg;\ndiff --git a/builtin/mktag.c b/builtin/mktag.c\nindex f40264a878..37c17e6beb 100644\n--- a/builtin/mktag.c\n+++ b/builtin/mktag.c\n@@ -50,7 +50,7 @@ static int verify_object_in_tag(struct object_id *tagged_oid, int *tagged_type)\n {\n \tint ret;\n \tenum object_type type;\n-\tunsigned long size;\n+\tsize_t size;\n \tvoid *buffer;\n \tconst struct object_id *repl;\n \ndiff --git a/builtin/notes.c b/builtin/notes.c\nindex 9af602bdd7..962df867c8 100644\n--- a/builtin/notes.c\n+++ b/builtin/notes.c\n@@ -150,7 +150,7 @@ static int list_each_note(const struct object_id *object_oid,\n \n static void copy_obj_to_fd(int fd, const struct object_id *oid)\n {\n-\tunsigned long size;\n+\tsize_t size;\n \tenum object_type type;\n \tchar *buf = odb_read_object(the_repository->objects, oid, &type, &size);\n \tif (buf) {\n@@ -313,7 +313,7 @@ static int parse_reuse_arg(const struct option *opt, const char *arg, int unset)\n \tchar *value;\n \tstruct object_id object;\n \tenum object_type type;\n-\tunsigned long len;\n+\tsize_t len;\n \n \tBUG_ON_OPT_NEG(unset);\n \n@@ -721,7 +721,7 @@ static int append_edit(int argc, const char **argv, const char *prefix,\n \n \tif (note && !edit) {\n \t\t/* Append buf to previous note contents */\n-\t\tunsigned long size;\n+\t\tsize_t size;\n \t\tenum object_type type;\n \t\tstruct strbuf buf = STRBUF_INIT;\n \t\tchar *prev_buf = odb_read_object(the_repository->objects, note, &type, &size);\ndiff --git a/builtin/pack-objects.c b/builtin/pack-objects.c\nindex bb372d0b03..6202fe4dca 100644\n--- a/builtin/pack-objects.c\n+++ b/builtin/pack-objects.c\n@@ -356,14 +356,17 @@ static void *get_delta(struct object_entry *entry)\n \tunsigned long size, base_size, delta_size;\n \tvoid *buf, *base_buf, *delta_buf;\n \tenum object_type type;\n+\tsize_t size_st = 0, base_size_st = 0;\n \n \tbuf = odb_read_object(the_repository->objects, &entry->idx.oid,\n-\t\t\t      &type, &size);\n+\t\t\t      &type, &size_st);\n+\tsize = cast_size_t_to_ulong(size_st);\n \tif (!buf)\n \t\tdie(_(\"unable to read %s\"), oid_to_hex(&entry->idx.oid));\n \tbase_buf = odb_read_object(the_repository->objects,\n \t\t\t\t   &DELTA(entry)->idx.oid, &type,\n-\t\t\t\t   &base_size);\n+\t\t\t\t   &base_size_st);\n+\tbase_size = cast_size_t_to_ulong(base_size_st);\n \tif (!base_buf)\n \t\tdie(\"unable to read %s\",\n \t\t    oid_to_hex(&DELTA(entry)->idx.oid));\n@@ -528,9 +531,11 @@ static unsigned long write_no_reuse_object(struct hashfile *f, struct object_ent\n \t\t\ttype = st->type;\n \t\t\tsize = st->size;\n \t\t} else {\n+\t\t\tsize_t size_st = 0;\n \t\t\tbuf = odb_read_object(the_repository->objects,\n \t\t\t\t\t      &entry->idx.oid, &type,\n-\t\t\t\t\t      &size);\n+\t\t\t\t\t      &size_st);\n+\t\t\tsize = cast_size_t_to_ulong(size_st);\n \t\t\tif (!buf)\n \t\t\t\tdie(_(\"unable to read %s\"),\n \t\t\t\t    oid_to_hex(&entry->idx.oid));\n@@ -1935,6 +1940,7 @@ static struct pbase_tree_cache *pbase_tree_get(const struct object_id *oid)\n \tstruct pbase_tree_cache *ent, *nent;\n \tvoid *data;\n \tunsigned long size;\n+\tsize_t size_st = 0;\n \tenum object_type type;\n \tint neigh;\n \tint my_ix = pbase_tree_cache_ix(oid);\n@@ -1962,7 +1968,8 @@ static struct pbase_tree_cache *pbase_tree_get(const struct object_id *oid)\n \t/* Did not find one.  Either we got a bogus request or\n \t * we need to read and perhaps cache.\n \t */\n-\tdata = odb_read_object(the_repository->objects, oid, &type, &size);\n+\tdata = odb_read_object(the_repository->objects, oid, &type, &size_st);\n+\tsize = cast_size_t_to_ulong(size_st);\n \tif (!data)\n \t\treturn NULL;\n \tif (type != OBJ_TREE) {\n@@ -2117,13 +2124,15 @@ static void add_preferred_base(struct object_id *oid)\n \tstruct pbase_tree *it;\n \tvoid *data;\n \tunsigned long size;\n+\tsize_t size_st = 0;\n \tstruct object_id tree_oid;\n \n \tif (window <= num_preferred_base++)\n \t\treturn;\n \n \tdata = odb_read_object_peeled(the_repository->objects, oid,\n-\t\t\t\t      OBJ_TREE, &size, &tree_oid);\n+\t\t\t\t      OBJ_TREE, &size_st, &tree_oid);\n+\tsize = cast_size_t_to_ulong(size_st);\n \tif (!data)\n \t\treturn;\n \n@@ -2235,7 +2244,7 @@ static void prefetch_to_pack(uint32_t object_index_start) {\n \n static void check_object(struct object_entry *entry, uint32_t object_index)\n {\n-\tunsigned long canonical_size;\n+\tsize_t canonical_size;\n \tenum object_type type;\n \tstruct object_info oi = {.typep = &type, .sizep = &canonical_size};\n \n@@ -2434,7 +2443,7 @@ static void drop_reused_delta(struct object_entry *entry)\n \tunsigned *idx = &to_pack.objects[entry->delta_idx - 1].delta_child_idx;\n \tstruct object_info oi = OBJECT_INFO_INIT;\n \tenum object_type type;\n-\tunsigned long size;\n+\tsize_t size;\n \n \twhile (*idx) {\n \t\tstruct object_entry *oe = &to_pack.objects[*idx - 1];\n@@ -2746,7 +2755,7 @@ size_t oe_get_size_slow(struct packing_data *pack,\n \tsize_t size;\n \n \tif (e->type_ != OBJ_OFS_DELTA && e->type_ != OBJ_REF_DELTA) {\n-\t\tunsigned long sz;\n+\t\tsize_t sz;\n \t\tpacking_data_lock(&to_pack);\n \t\tif (odb_read_object_info(the_repository->objects,\n \t\t\t\t\t &e->idx.oid, &sz) < 0)\n@@ -2831,10 +2840,12 @@ static int try_delta(struct unpacked *trg, struct unpacked *src,\n \n \t/* Load data if not already done */\n \tif (!trg->data) {\n+\t\tsize_t sz_st = 0;\n \t\tpacking_data_lock(&to_pack);\n \t\ttrg->data = odb_read_object(the_repository->objects,\n \t\t\t\t\t    &trg_entry->idx.oid, &type,\n-\t\t\t\t\t    &sz);\n+\t\t\t\t\t    &sz_st);\n+\t\tsz = cast_size_t_to_ulong(sz_st);\n \t\tpacking_data_unlock(&to_pack);\n \t\tif (!trg->data)\n \t\t\tdie(_(\"object %s cannot be read\"),\n@@ -2846,10 +2857,12 @@ static int try_delta(struct unpacked *trg, struct unpacked *src,\n \t\t*mem_usage += sz;\n \t}\n \tif (!src->data) {\n+\t\tsize_t sz_st = 0;\n \t\tpacking_data_lock(&to_pack);\n \t\tsrc->data = odb_read_object(the_repository->objects,\n \t\t\t\t\t    &src_entry->idx.oid, &type,\n-\t\t\t\t\t    &sz);\n+\t\t\t\t\t    &sz_st);\n+\t\tsz = cast_size_t_to_ulong(sz_st);\n \t\tpacking_data_unlock(&to_pack);\n \t\tif (!src->data) {\n \t\t\tif (src_entry->preferred_base) {\ndiff --git a/builtin/repo.c b/builtin/repo.c\nindex 71a5c1c29c..69f3626467 100644\n--- a/builtin/repo.c\n+++ b/builtin/repo.c\n@@ -784,13 +784,14 @@ static int count_objects(const char *path UNUSED, struct oid_array *oids,\n \tfor (size_t i = 0; i < oids->nr; i++) {\n \t\tstruct object_info oi = OBJECT_INFO_INIT;\n \t\tunsigned long inflated;\n+\t\tsize_t inflated_st = 0;\n \t\tstruct commit *commit;\n \t\tstruct object *obj;\n \t\tvoid *content;\n \t\toff_t disk;\n \t\tint eaten;\n \n-\t\toi.sizep = &inflated;\n+\t\toi.sizep = &inflated_st;\n \t\toi.disk_sizep = &disk;\n \t\toi.contentp = &content;\n \n@@ -798,6 +799,7 @@ static int count_objects(const char *path UNUSED, struct oid_array *oids,\n \t\t\t\t\t\t  OBJECT_INFO_SKIP_FETCH_OBJECT |\n \t\t\t\t\t\t  OBJECT_INFO_QUICK) < 0)\n \t\t\tcontinue;\n+\t\tinflated = cast_size_t_to_ulong(inflated_st);\n \n \t\tobj = parse_object_buffer(the_repository, &oids->oid[i], type,\n \t\t\t\t\t  inflated, content, &eaten);\ndiff --git a/builtin/tag.c b/builtin/tag.c\nindex d51c2e3349..06c125b53c 100644\n--- a/builtin/tag.c\n+++ b/builtin/tag.c\n@@ -238,7 +238,7 @@ static int git_tag_config(const char *var, const char *value,\n \n static void write_tag_body(int fd, const struct object_id *oid)\n {\n-\tunsigned long size;\n+\tsize_t size;\n \tenum object_type type;\n \tchar *buf, *sp, *orig;\n \tstruct strbuf payload = STRBUF_INIT;\n@@ -388,7 +388,7 @@ static void create_reflog_msg(const struct object_id *oid, struct strbuf *sb)\n \tenum object_type type;\n \tstruct commit *c;\n \tchar *buf;\n-\tunsigned long size;\n+\tsize_t size;\n \tint subject_len = 0;\n \tconst char *subject_start;\n \ndiff --git a/builtin/unpack-file.c b/builtin/unpack-file.c\nindex 87877a9fab..387389ed49 100644\n--- a/builtin/unpack-file.c\n+++ b/builtin/unpack-file.c\n@@ -12,7 +12,7 @@ static char *create_temp_file(struct object_id *oid)\n \tstatic char path[50];\n \tvoid *buf;\n \tenum object_type type;\n-\tunsigned long size;\n+\tsize_t size;\n \tint fd;\n \n \tbuf = odb_read_object(the_repository->objects, oid, &type, &size);\ndiff --git a/builtin/unpack-objects.c b/builtin/unpack-objects.c\nindex e7a50c493c..f3849bb654 100644\n--- a/builtin/unpack-objects.c\n+++ b/builtin/unpack-objects.c\n@@ -231,7 +231,7 @@ static int check_object(struct object *obj, enum object_type type,\n \t\tdie(\"object type mismatch\");\n \n \tif (!(obj->flags & FLAG_OPEN)) {\n-\t\tunsigned long size;\n+\t\tsize_t size;\n \t\tint type = odb_read_object_info(the_repository->objects, &obj->oid, &size);\n \t\tif (type != obj->type || type <= 0)\n \t\t\tdie(\"object of unexpected type\");\n@@ -436,6 +436,7 @@ static void unpack_delta_entry(enum object_type type, unsigned long delta_size,\n {\n \tvoid *delta_data, *base;\n \tunsigned long base_size;\n+\tsize_t base_size_st = 0;\n \tstruct object_id base_oid;\n \n \tif (type == OBJ_REF_DELTA) {\n@@ -512,7 +513,8 @@ static void unpack_delta_entry(enum object_type type, unsigned long delta_size,\n \t\treturn;\n \n \tbase = odb_read_object(the_repository->objects, &base_oid,\n-\t\t\t       &type, &base_size);\n+\t\t\t       &type, &base_size_st);\n+\tbase_size = cast_size_t_to_ulong(base_size_st);\n \tif (!base) {\n \t\terror(\"failed to read delta-pack base object %s\",\n \t\t      oid_to_hex(&base_oid));\ndiff --git a/bundle.c b/bundle.c\nindex 42327f9739..fd2db2c837 100644\n--- a/bundle.c\n+++ b/bundle.c\n@@ -296,7 +296,7 @@ int list_bundle_refs(struct bundle_header *header, int argc, const char **argv)\n \n static int is_tag_in_date_range(struct object *tag, struct rev_info *revs)\n {\n-\tunsigned long size;\n+\tsize_t size;\n \tenum object_type type;\n \tchar *buf = NULL, *line, *lineend;\n \ttimestamp_t date;\ndiff --git a/combine-diff.c b/combine-diff.c\nindex b799862068..3ce71db8bb 100644\n--- a/combine-diff.c\n+++ b/combine-diff.c\n@@ -325,7 +325,9 @@ static char *grab_blob(struct repository *r,\n \t\t*size = fill_textconv(r, textconv, df, &blob);\n \t\tfree_filespec(df);\n \t} else {\n-\t\tblob = odb_read_object(r->objects, oid, &type, size);\n+\t\tsize_t size_st = 0;\n+\t\tblob = odb_read_object(r->objects, oid, &type, &size_st);\n+\t\t*size = cast_size_t_to_ulong(size_st);\n \t\tif (!blob)\n \t\t\tdie(_(\"unable to read %s\"), oid_to_hex(oid));\n \t\tif (type != OBJ_BLOB)\ndiff --git a/commit.c b/commit.c\nindex fd8723502e..7950effc58 100644\n--- a/commit.c\n+++ b/commit.c\n@@ -395,7 +395,7 @@ const void *repo_get_commit_buffer(struct repository *r,\n \tconst void *ret = get_cached_commit_buffer(r, commit, sizep);\n \tif (!ret) {\n \t\tenum object_type type;\n-\t\tunsigned long size;\n+\t\tsize_t size;\n \t\tret = odb_read_object(r->objects, &commit->object.oid, &type, &size);\n \t\tif (!ret)\n \t\t\tdie(\"cannot read commit object %s\",\n@@ -404,7 +404,7 @@ const void *repo_get_commit_buffer(struct repository *r,\n \t\t\tdie(\"expected commit for %s, got %s\",\n \t\t\t    oid_to_hex(&commit->object.oid), type_name(type));\n \t\tif (sizep)\n-\t\t\t*sizep = size;\n+\t\t\t*sizep = cast_size_t_to_ulong(size);\n \t}\n \treturn ret;\n }\n@@ -437,7 +437,7 @@ static inline void set_commit_tree(struct commit *c, struct tree *t)\n static void load_tree_from_commit_contents(struct repository *r, struct commit *commit)\n {\n \tenum object_type type;\n-\tunsigned long size;\n+\tsize_t size;\n \tchar *buf;\n \tconst char *p;\n \tstruct object_id tree_oid;\n@@ -604,7 +604,7 @@ int repo_parse_commit_internal(struct repository *r,\n {\n \tenum object_type type;\n \tvoid *buffer;\n-\tunsigned long size;\n+\tsize_t size;\n \tstruct object_info oi = {\n \t\t.typep = &type,\n \t\t.sizep = &size,\n@@ -1313,7 +1313,7 @@ static void handle_signed_tag(const struct commit *parent, struct commit_extra_h\n \tstruct merge_remote_desc *desc;\n \tstruct commit_extra_header *mergetag;\n \tchar *buf;\n-\tunsigned long size;\n+\tsize_t size;\n \tenum object_type type;\n \tstruct strbuf payload = STRBUF_INIT;\n \tstruct strbuf signature = STRBUF_INIT;\ndiff --git a/config.c b/config.c\nindex a1b92fe083..21b231052c 100644\n--- a/config.c\n+++ b/config.c\n@@ -1442,7 +1442,7 @@ int git_config_from_blob_oid(config_fn_t fn,\n {\n \tenum object_type type;\n \tchar *buf;\n-\tunsigned long size;\n+\tsize_t size;\n \tint ret;\n \n \tbuf = odb_read_object(repo->objects, oid, &type, &size);\ndiff --git a/diff.c b/diff.c\nindex 5a584fa1d5..816b89dc6c 100644\n--- a/diff.c\n+++ b/diff.c\n@@ -4594,8 +4594,9 @@ int diff_populate_filespec(struct repository *r,\n \t\t}\n \t}\n \telse {\n+\t\tsize_t size_st = 0;\n \t\tstruct object_info info = {\n-\t\t\t.sizep = &s->size\n+\t\t\t.sizep = &size_st\n \t\t};\n \n \t\tif (!(size_only || check_binary))\n@@ -4617,6 +4618,7 @@ int diff_populate_filespec(struct repository *r,\n \t\t\tdie(\"unable to read %s\", oid_to_hex(&s->oid));\n \n object_read:\n+\t\ts->size = cast_size_t_to_ulong(size_st);\n \t\tif (size_only || check_binary) {\n \t\t\tif (size_only)\n \t\t\t\treturn 0;\n@@ -4631,6 +4633,7 @@ object_read:\n \t\t\tif (odb_read_object_info_extended(r->objects, &s->oid, &info,\n \t\t\t\t\t\t\t  OBJECT_INFO_LOOKUP_REPLACE))\n \t\t\t\tdie(\"unable to read %s\", oid_to_hex(&s->oid));\n+\t\t\ts->size = cast_size_t_to_ulong(size_st);\n \t\t}\n \t\ts->should_free = 1;\n \t}\ndiff --git a/dir.c b/dir.c\nindex 33c81c256e..b6764d98a7 100644\n--- a/dir.c\n+++ b/dir.c\n@@ -324,7 +324,7 @@ static int do_read_blob(const struct object_id *oid, struct oid_stat *oid_stat,\n \t\t\tsize_t *size_out, char **data_out)\n {\n \tenum object_type type;\n-\tunsigned long sz;\n+\tsize_t sz;\n \tchar *data;\n \n \t*size_out = 0;\ndiff --git a/entry.c b/entry.c\nindex 7817aee362..c444fe5a10 100644\n--- a/entry.c\n+++ b/entry.c\n@@ -92,11 +92,9 @@ static int create_file(const char *path, unsigned int mode)\n void *read_blob_entry(const struct cache_entry *ce, size_t *size)\n {\n \tenum object_type type;\n-\tunsigned long ul;\n \tvoid *blob_data = odb_read_object(the_repository->objects, &ce->oid,\n-\t\t\t\t\t  &type, &ul);\n+\t\t\t\t\t  &type, size);\n \n-\t*size = ul;\n \tif (blob_data) {\n \t\tif (type == OBJ_BLOB)\n \t\t\treturn blob_data;\ndiff --git a/fmt-merge-msg.c b/fmt-merge-msg.c\nindex 45d8b20e97..14441f23ae 100644\n--- a/fmt-merge-msg.c\n+++ b/fmt-merge-msg.c\n@@ -528,11 +528,11 @@ static void fmt_merge_msg_sigs(struct strbuf *out)\n \tfor (i = 0; i < origins.nr; i++) {\n \t\tstruct object_id *oid = origins.items[i].util;\n \t\tenum object_type type;\n-\t\tunsigned long size;\n+\t\tsize_t size;\n \t\tchar *buf = odb_read_object(the_repository->objects, oid,\n \t\t\t\t\t    &type, &size);\n \t\tchar *origbuf = buf;\n-\t\tunsigned long len = size;\n+\t\tsize_t len = size;\n \t\tstruct signature_check sigc = { NULL };\n \t\tstruct strbuf payload = STRBUF_INIT, sig = STRBUF_INIT;\n \ndiff --git a/fsck.c b/fsck.c\nindex b72200c352..82c2002f4a 100644\n--- a/fsck.c\n+++ b/fsck.c\n@@ -1328,7 +1328,7 @@ static int fsck_blobs(struct oidset *blobs_found, struct oidset *blobs_done,\n \toidset_iter_init(blobs_found, &iter);\n \twhile ((oid = oidset_iter_next(&iter))) {\n \t\tenum object_type type;\n-\t\tunsigned long size;\n+\t\tsize_t size;\n \t\tchar *buf;\n \n \t\tif (oidset_contains(blobs_done, oid))\ndiff --git a/grep.c b/grep.c\nindex a54e5d86a9..1d75d31421 100644\n--- a/grep.c\n+++ b/grep.c\n@@ -1931,9 +1931,11 @@ void grep_source_clear_data(struct grep_source *gs)\n static int grep_source_load_oid(struct grep_source *gs)\n {\n \tenum object_type type;\n+\tsize_t size_st = 0;\n \n \tgs->buf = odb_read_object(gs->repo->objects, gs->identifier,\n-\t\t\t\t  &type, &gs->size);\n+\t\t\t\t  &type, &size_st);\n+\tgs->size = cast_size_t_to_ulong(size_st);\n \tif (!gs->buf)\n \t\treturn error(_(\"'%s': unable to read %s\"),\n \t\t\t     gs->name,\ndiff --git a/http-push.c b/http-push.c\nindex 520d6c3b6a..c61d9f7e02 100644\n--- a/http-push.c\n+++ b/http-push.c\n@@ -365,7 +365,7 @@ static void start_put(struct transfer_request *request)\n \tenum object_type type;\n \tchar hdr[50];\n \tvoid *unpacked;\n-\tunsigned long len;\n+\tsize_t len;\n \tint hdrlen;\n \tssize_t size;\n \tgit_zstream stream;\ndiff --git a/list-objects-filter.c b/list-objects-filter.c\nindex 78316e7f90..c912ff3079 100644\n--- a/list-objects-filter.c\n+++ b/list-objects-filter.c\n@@ -280,7 +280,7 @@ static enum list_objects_filter_result filter_blobs_limit(\n \tvoid *filter_data_)\n {\n \tstruct filter_blobs_limit_data *filter_data = filter_data_;\n-\tunsigned long object_length;\n+\tsize_t object_length;\n \tenum object_type t;\n \n \tswitch (filter_situation) {\ndiff --git a/mailmap.c b/mailmap.c\nindex 3b2691781d..72b639e602 100644\n--- a/mailmap.c\n+++ b/mailmap.c\n@@ -186,7 +186,7 @@ int read_mailmap_blob(struct repository *repo, struct string_list *map,\n {\n \tstruct object_id oid;\n \tchar *buf;\n-\tunsigned long size;\n+\tsize_t size;\n \tenum object_type type;\n \n \tif (!name)\ndiff --git a/match-trees.c b/match-trees.c\nindex 4216933d06..2a43c0fa1a 100644\n--- a/match-trees.c\n+++ b/match-trees.c\n@@ -61,7 +61,7 @@ static void *fill_tree_desc_strict(struct repository *r,\n {\n \tvoid *buffer;\n \tenum object_type type;\n-\tunsigned long size;\n+\tsize_t size;\n \n \tbuffer = odb_read_object(r->objects, hash, &type, &size);\n \tif (!buffer)\n@@ -186,7 +186,7 @@ static int splice_tree(struct repository *r,\n \tchar *subpath;\n \tint toplen;\n \tchar *buf;\n-\tunsigned long sz;\n+\tsize_t sz;\n \tstruct tree_desc desc;\n \tunsigned char *rewrite_here;\n \tconst struct object_id *rewrite_with;\ndiff --git a/merge-blobs.c b/merge-blobs.c\nindex 6fc2799417..16a75bd1e3 100644\n--- a/merge-blobs.c\n+++ b/merge-blobs.c\n@@ -9,7 +9,7 @@\n static int fill_mmfile_blob(mmfile_t *f, struct blob *obj)\n {\n \tvoid *buf;\n-\tunsigned long size;\n+\tsize_t size;\n \tenum object_type type;\n \n \tbuf = odb_read_object(the_repository->objects, &obj->object.oid,\n@@ -35,7 +35,7 @@ static void *three_way_filemerge(struct index_state *istate,\n \t\t\t\t mmfile_t *base,\n \t\t\t\t mmfile_t *our,\n \t\t\t\t mmfile_t *their,\n-\t\t\t\t unsigned long *size)\n+\t\t\t\t size_t *size)\n {\n \tenum ll_merge_result merge_status;\n \tmmbuffer_t res;\n@@ -61,7 +61,7 @@ static void *three_way_filemerge(struct index_state *istate,\n \n void *merge_blobs(struct index_state *istate, const char *path,\n \t\t  struct blob *base, struct blob *our,\n-\t\t  struct blob *their, unsigned long *size)\n+\t\t  struct blob *their, size_t *size)\n {\n \tvoid *res = NULL;\n \tmmfile_t f1, f2, common;\ndiff --git a/merge-blobs.h b/merge-blobs.h\nindex 13cf9669e5..5797517a06 100644\n--- a/merge-blobs.h\n+++ b/merge-blobs.h\n@@ -6,6 +6,6 @@ struct index_state;\n \n void *merge_blobs(struct index_state *, const char *,\n \t\t  struct blob *, struct blob *,\n-\t\t  struct blob *, unsigned long *);\n+\t\t  struct blob *, size_t *);\n \n #endif /* MERGE_BLOBS_H */\ndiff --git a/merge-ort.c b/merge-ort.c\nindex 544be9e466..4f6273bd51 100644\n--- a/merge-ort.c\n+++ b/merge-ort.c\n@@ -3716,7 +3716,7 @@ static int read_oid_strbuf(struct merge_options *opt,\n {\n \tvoid *buf;\n \tenum object_type type;\n-\tunsigned long size;\n+\tsize_t size;\n \tbuf = odb_read_object(opt->repo->objects, oid, &type, &size);\n \tif (!buf) {\n \t\tpath_msg(opt, ERROR_OBJECT_READ_FAILED, 0,\ndiff --git a/notes-cache.c b/notes-cache.c\nindex bf5bb1f6c1..74cef802bd 100644\n--- a/notes-cache.c\n+++ b/notes-cache.c\n@@ -82,7 +82,7 @@ char *notes_cache_get(struct notes_cache *c, struct object_id *key_oid,\n \tconst struct object_id *value_oid;\n \tenum object_type type;\n \tchar *value;\n-\tunsigned long size;\n+\tsize_t size;\n \n \tvalue_oid = get_note(&c->tree, key_oid);\n \tif (!value_oid)\ndiff --git a/notes-merge.c b/notes-merge.c\nindex b9322abbcb..118cad2518 100644\n--- a/notes-merge.c\n+++ b/notes-merge.c\n@@ -339,7 +339,7 @@ static void write_note_to_worktree(const struct object_id *obj,\n \t\t\t\t   const struct object_id *note)\n {\n \tenum object_type type;\n-\tunsigned long size;\n+\tsize_t size;\n \tvoid *buf = odb_read_object(the_repository->objects, note, &type, &size);\n \n \tif (!buf)\ndiff --git a/notes.c b/notes.c\nindex 8f315e2a00..ec9c2cb150 100644\n--- a/notes.c\n+++ b/notes.c\n@@ -811,7 +811,8 @@ int combine_notes_concatenate(struct object_id *cur_oid,\n \t\t\t      const struct object_id *new_oid)\n {\n \tchar *cur_msg = NULL, *new_msg = NULL, *buf;\n-\tunsigned long cur_len, new_len, buf_len;\n+\tunsigned long buf_len;\n+\tsize_t cur_len, new_len;\n \tenum object_type cur_type, new_type;\n \tint ret;\n \n@@ -875,7 +876,7 @@ static int string_list_add_note_lines(struct string_list *list,\n \t\t\t\t      const struct object_id *oid)\n {\n \tchar *data;\n-\tunsigned long len;\n+\tsize_t len;\n \tenum object_type t;\n \n \tif (is_null_oid(oid))\n@@ -1282,7 +1283,8 @@ static void format_note(struct notes_tree *t, const struct object_id *object_oid\n \tstatic const char utf8[] = \"utf-8\";\n \tconst struct object_id *oid;\n \tchar *msg, *msg_p;\n-\tunsigned long linelen, msglen;\n+\tunsigned long linelen;\n+\tsize_t msglen;\n \tenum object_type type;\n \n \tif (!t)\ndiff --git a/object-file.c b/object-file.c\nindex 90f995d000..a81d50c305 100644\n--- a/object-file.c\n+++ b/object-file.c\n@@ -381,7 +381,7 @@ static int parse_loose_header(const char *hdr, struct object_info *oi)\n \t}\n \n \tif (oi->sizep)\n-\t\t*oi->sizep = cast_size_t_to_ulong(size);\n+\t\t*oi->sizep = size;\n \n \t/*\n \t * The length must be followed by a zero byte\n@@ -409,7 +409,7 @@ static int read_object_info_from_path(struct odb_source *source,\n \tvoid *map = NULL;\n \tgit_zstream stream, *stream_to_end = NULL;\n \tchar hdr[MAX_HEADER_LEN];\n-\tunsigned long size_scratch;\n+\tsize_t size_scratch;\n \tenum object_type type_scratch;\n \tstruct stat st;\n \n@@ -1222,7 +1222,7 @@ int force_object_loose(struct odb_source *source,\n {\n \tconst struct git_hash_algo *compat = source->odb->repo->compat_hash_algo;\n \tvoid *buf;\n-\tunsigned long len;\n+\tsize_t len;\n \tstruct object_info oi = OBJECT_INFO_INIT;\n \tstruct object_id compat_oid;\n \tenum object_type type;\n@@ -2126,7 +2126,7 @@ int read_loose_object(struct repository *repo,\n \tunsigned long mapsize;\n \tgit_zstream stream;\n \tchar hdr[MAX_HEADER_LEN];\n-\tunsigned long *size = oi->sizep;\n+\tsize_t *size = oi->sizep;\n \n \tfd = git_open(path);\n \tif (fd >= 0)\n@@ -2302,7 +2302,6 @@ int odb_source_loose_read_object_stream(struct odb_read_stream **out,\n \tstruct object_info oi = OBJECT_INFO_INIT;\n \tstruct odb_loose_read_stream *st;\n \tunsigned long mapsize;\n-\tunsigned long size_ul;\n \tvoid *mapped;\n \n \tmapped = odb_source_loose_map_object(source, oid, &mapsize);\n@@ -2326,18 +2325,11 @@ int odb_source_loose_read_object_stream(struct odb_read_stream **out,\n \t\tgoto error;\n \t}\n \n-\t/*\n-\t * object_info.sizep is unsigned long* (32-bit on Windows), but\n-\t * st->base.size is size_t (64-bit). Use temporary variable.\n-\t * Note: loose objects >4GB would still truncate here, but such\n-\t * large loose objects are uncommon (they'd normally be packed).\n-\t */\n-\toi.sizep = &size_ul;\n+\toi.sizep = &st->base.size;\n \toi.typep = &st->base.type;\n \n \tif (parse_loose_header(st->hdr, &oi) < 0 || st->base.type < 0)\n \t\tgoto error;\n-\tst->base.size = size_ul;\n \n \tst->mapped = mapped;\n \tst->mapsize = mapsize;\ndiff --git a/object.c b/object.c\nindex 465902ecc6..23b84aa7e2 100644\n--- a/object.c\n+++ b/object.c\n@@ -325,7 +325,7 @@ struct object *parse_object_with_flags(struct repository *r,\n {\n \tint skip_hash = !!(flags & PARSE_OBJECT_SKIP_HASH_CHECK);\n \tint discard_tree = !!(flags & PARSE_OBJECT_DISCARD_TREE);\n-\tunsigned long size;\n+\tsize_t size;\n \tenum object_type type;\n \tint eaten;\n \tconst struct object_id *repl = lookup_replace_object(r, oid);\ndiff --git a/odb.c b/odb.c\nindex 965ef68e4e..7d555be09f 100644\n--- a/odb.c\n+++ b/odb.c\n@@ -625,7 +625,7 @@ static int oid_object_info_convert(struct repository *r,\n \tenum object_type type;\n \tstruct object_id oid, delta_base_oid;\n \tstruct object_info new_oi, *oi;\n-\tunsigned long size;\n+\tsize_t size;\n \tvoid *content;\n \tint ret;\n \n@@ -716,7 +716,7 @@ int odb_read_object_info_extended(struct object_database *odb,\n /* returns enum object_type or negative */\n int odb_read_object_info(struct object_database *odb,\n \t\t\t const struct object_id *oid,\n-\t\t\t unsigned long *sizep)\n+\t\t\t size_t *sizep)\n {\n \tenum object_type type;\n \tstruct object_info oi = OBJECT_INFO_INIT;\n@@ -730,7 +730,7 @@ int odb_read_object_info(struct object_database *odb,\n }\n \n int odb_pretend_object(struct object_database *odb,\n-\t\t       void *buf, unsigned long len, enum object_type type,\n+\t\t       void *buf, size_t len, enum object_type type,\n \t\t       struct object_id *oid)\n {\n \thash_object_file(odb->repo->hash_algo, buf, len, type, oid);\n@@ -744,7 +744,7 @@ int odb_pretend_object(struct object_database *odb,\n void *odb_read_object(struct object_database *odb,\n \t\t      const struct object_id *oid,\n \t\t      enum object_type *type,\n-\t\t      unsigned long *size)\n+\t\t      size_t *size)\n {\n \tstruct object_info oi = OBJECT_INFO_INIT;\n \tunsigned flags = OBJECT_INFO_DIE_IF_CORRUPT | OBJECT_INFO_LOOKUP_REPLACE;\n@@ -762,12 +762,12 @@ void *odb_read_object(struct object_database *odb,\n void *odb_read_object_peeled(struct object_database *odb,\n \t\t\t     const struct object_id *oid,\n \t\t\t     enum object_type required_type,\n-\t\t\t     unsigned long *size,\n+\t\t\t     size_t *size,\n \t\t\t     struct object_id *actual_oid_return)\n {\n \tenum object_type type;\n \tvoid *buffer;\n-\tunsigned long isize;\n+\tsize_t isize;\n \tstruct object_id actual_oid;\n \n \toidcpy(&actual_oid, oid);\ndiff --git a/odb.h b/odb.h\nindex 73553ed5a7..e2f0bbad25 100644\n--- a/odb.h\n+++ b/odb.h\n@@ -228,12 +228,12 @@ struct odb_source *odb_add_to_alternates_memory(struct object_database *odb,\n void *odb_read_object(struct object_database *odb,\n \t\t      const struct object_id *oid,\n \t\t      enum object_type *type,\n-\t\t      unsigned long *size);\n+\t\t      size_t *size);\n \n void *odb_read_object_peeled(struct object_database *odb,\n \t\t\t     const struct object_id *oid,\n \t\t\t     enum object_type required_type,\n-\t\t\t     unsigned long *size,\n+\t\t\t     size_t *size,\n \t\t\t     struct object_id *oid_ret);\n \n /*\n@@ -245,13 +245,13 @@ void *odb_read_object_peeled(struct object_database *odb,\n  * that reference it.\n  */\n int odb_pretend_object(struct object_database *odb,\n-\t\t       void *buf, unsigned long len, enum object_type type,\n+\t\t       void *buf, size_t len, enum object_type type,\n \t\t       struct object_id *oid);\n \n struct object_info {\n \t/* Request */\n \tenum object_type *typep;\n-\tunsigned long *sizep;\n+\tsize_t *sizep;\n \toff_t *disk_sizep;\n \tstruct object_id *delta_base_oid;\n \tvoid **contentp;\n@@ -356,7 +356,7 @@ int odb_read_object_info_extended(struct object_database *odb,\n  */\n int odb_read_object_info(struct object_database *odb,\n \t\t\t const struct object_id *oid,\n-\t\t\t unsigned long *sizep);\n+\t\t\t size_t *sizep);\n \n enum odb_has_object_flags {\n \t/* Retry packed storage after checking packed and loose storage */\ndiff --git a/odb/streaming.c b/odb/streaming.c\nindex 7602a8d5d8..20531e864c 100644\n--- a/odb/streaming.c\n+++ b/odb/streaming.c\n@@ -157,26 +157,15 @@ static int open_istream_incore(struct odb_read_stream **out,\n \t\t.base.read = read_istream_incore,\n \t};\n \tstruct odb_incore_read_stream *st;\n-\tunsigned long size_ul;\n \tint ret;\n \n \toi.typep = &stream.base.type;\n-\t/*\n-\t * object_info.sizep is unsigned long* (32-bit on Windows), but\n-\t * stream.base.size is size_t (64-bit). We use a temporary variable\n-\t * because the types are incompatible. Note: this path still truncates\n-\t * for >4GB objects, but large objects should use pack streaming\n-\t * (packfile_store_read_object_stream) which handles size_t properly.\n-\t * This incore fallback is only used for small objects or when pack\n-\t * streaming is unavailable.\n-\t */\n-\toi.sizep = &size_ul;\n+\toi.sizep = &stream.base.size;\n \toi.contentp = (void **)&stream.buf;\n \tret = odb_read_object_info_extended(odb, oid, &oi,\n \t\t\t\t\t    OBJECT_INFO_DIE_IF_CORRUPT);\n \tif (ret)\n \t\treturn ret;\n-\tstream.base.size = size_ul;\n \n \tCALLOC_ARRAY(st, 1);\n \t*st = stream;\ndiff --git a/pack-bitmap.c b/pack-bitmap.c\nindex f9af8a96bd..e8a82945cc 100644\n--- a/pack-bitmap.c\n+++ b/pack-bitmap.c\n@@ -1856,7 +1856,7 @@ static void filter_bitmap_blob_none(struct bitmap_index *bitmap_git,\n static unsigned long get_size_by_pos(struct bitmap_index *bitmap_git,\n \t\t\t\t     uint32_t pos)\n {\n-\tunsigned long size;\n+\tsize_t size;\n \tstruct object_info oi = OBJECT_INFO_INIT;\n \n \toi.sizep = &size;\n@@ -1891,7 +1891,7 @@ static unsigned long get_size_by_pos(struct bitmap_index *bitmap_git,\n \t\t\tdie(_(\"unable to get size of %s\"), oid_to_hex(&obj->oid));\n \t}\n \n-\treturn size;\n+\treturn cast_size_t_to_ulong(size);\n }\n \n static void filter_bitmap_blob_limit(struct bitmap_index *bitmap_git,\ndiff --git a/packfile.c b/packfile.c\nindex c174982d10..78c389e6f3 100644\n--- a/packfile.c\n+++ b/packfile.c\n@@ -1607,13 +1607,10 @@ static int packed_object_info_with_index_pos(struct packed_git *p, off_t obj_off\n \t * a \"real\" type later if the caller is interested.\n \t */\n \tif (oi->contentp) {\n-\t\tsize_t size_st = 0;\n \t\t*oi->contentp = cache_or_unpack_entry(p->repo, p, obj_offset,\n-\t\t\t\t\t\t      &size_st, &type);\n+\t\t\t\t\t\t      oi->sizep, &type);\n \t\tif (!*oi->contentp)\n \t\t\ttype = OBJ_BAD;\n-\t\telse if (oi->sizep)\n-\t\t\t*oi->sizep = cast_size_t_to_ulong(size_st);\n \t} else if (oi->sizep || oi->typep || oi->delta_base_oid) {\n \t\ttype = unpack_object_header(p, &w_curs, &curpos, &size);\n \t}\n@@ -1633,7 +1630,7 @@ static int packed_object_info_with_index_pos(struct packed_git *p, off_t obj_off\n \t\t\t\tgoto out;\n \t\t\t}\n \t\t}\n-\t\t*oi->sizep = (unsigned long)size;\n+\t\t*oi->sizep = size;\n \t}\n \n \tif (oi->disk_sizep || (oi->mtimep && p->is_cruft)) {\n@@ -1919,7 +1916,6 @@ void *unpack_entry(struct repository *r, struct packed_git *p, off_t obj_offset,\n \t\t\tstruct object_id base_oid;\n \t\t\tif (!(offset_to_pack_pos(p, obj_offset, &pos))) {\n \t\t\t\tstruct object_info oi = OBJECT_INFO_INIT;\n-\t\t\t\tunsigned long bsz_ul = 0;\n \n \t\t\t\tnth_packed_object_id(&base_oid, p,\n \t\t\t\t\t\t     pack_pos_to_index(p, pos));\n@@ -1930,13 +1926,11 @@ void *unpack_entry(struct repository *r, struct packed_git *p, off_t obj_offset,\n \t\t\t\tmark_bad_packed_object(p, &base_oid);\n \n \t\t\t\toi.typep = &type;\n-\t\t\t\toi.sizep = &bsz_ul;\n+\t\t\t\toi.sizep = &base_size;\n \t\t\t\toi.contentp = &base;\n \t\t\t\tif (odb_read_object_info_extended(r->objects, &base_oid,\n \t\t\t\t\t\t\t\t  &oi, 0) < 0)\n \t\t\t\t\tbase = NULL;\n-\t\t\t\telse\n-\t\t\t\t\tbase_size = bsz_ul;\n \n \t\t\t\texternal_base = base;\n \t\t\t}\ndiff --git a/path-walk.c b/path-walk.c\nindex 94ff90bd15..edc8e736d7 100644\n--- a/path-walk.c\n+++ b/path-walk.c\n@@ -368,7 +368,7 @@ static int walk_path(struct path_walk_context *ctx,\n \t\tstruct oid_array filtered = OID_ARRAY_INIT;\n \n \t\tfor (size_t i = 0; i < list->oids.nr; i++) {\n-\t\t\tunsigned long size;\n+\t\t\tsize_t size;\n \n \t\t\tif (odb_read_object_info(ctx->repo->objects,\n \t\t\t\t\t\t &list->oids.oid[i],\ndiff --git a/protocol-caps.c b/protocol-caps.c\nindex 35072ed60b..8858ea4489 100644\n--- a/protocol-caps.c\n+++ b/protocol-caps.c\n@@ -50,7 +50,7 @@ static void send_info(struct repository *r, struct packet_writer *writer,\n \tfor_each_string_list_item (item, oid_str_list) {\n \t\tconst char *oid_str = item->string;\n \t\tstruct object_id oid;\n-\t\tunsigned long object_size;\n+\t\tsize_t object_size;\n \n \t\tif (get_oid_hex_algop(oid_str, &oid, r->hash_algo) < 0) {\n \t\t\tpacket_writer_error(\n@@ -66,7 +66,8 @@ static void send_info(struct repository *r, struct packet_writer *writer,\n \t\t\tif (odb_read_object_info(r->objects, &oid, &object_size) < 0) {\n \t\t\t\tstrbuf_addstr(&send_buffer, \" \");\n \t\t\t} else {\n-\t\t\t\tstrbuf_addf(&send_buffer, \" %lu\", object_size);\n+\t\t\t\tstrbuf_addf(&send_buffer, \" %\"PRIuMAX,\n+\t\t\t\t\t    (uintmax_t)object_size);\n \t\t\t}\n \t\t}\n \ndiff --git a/read-cache.c b/read-cache.c\nindex 21829102ae..21ca58beea 100644\n--- a/read-cache.c\n+++ b/read-cache.c\n@@ -250,7 +250,7 @@ static int ce_compare_link(const struct cache_entry *ce, size_t expected_size)\n {\n \tint match = -1;\n \tvoid *buffer;\n-\tunsigned long size;\n+\tsize_t size;\n \tenum object_type type;\n \tstruct strbuf sb = STRBUF_INIT;\n \n@@ -3462,7 +3462,7 @@ void *read_blob_data_from_index(struct index_state *istate,\n \t\t\t\tconst char *path, unsigned long *size)\n {\n \tint pos, len;\n-\tunsigned long sz;\n+\tsize_t sz;\n \tenum object_type type;\n \tvoid *data;\n \n@@ -3490,7 +3490,7 @@ void *read_blob_data_from_index(struct index_state *istate,\n \t\treturn NULL;\n \t}\n \tif (size)\n-\t\t*size = sz;\n+\t\t*size = cast_size_t_to_ulong(sz);\n \treturn data;\n }\n \ndiff --git a/ref-filter.c b/ref-filter.c\nindex 1da4c0e60d..8ba91c72a1 100644\n--- a/ref-filter.c\n+++ b/ref-filter.c\n@@ -86,7 +86,7 @@ struct ref_trailer_buf {\n static struct expand_data {\n \tstruct object_id oid;\n \tenum object_type type;\n-\tunsigned long size;\n+\tsize_t size;\n \toff_t disk_size;\n \tstruct object_id delta_base_oid;\n \tvoid *content;\ndiff --git a/reflog.c b/reflog.c\nindex 82337078d0..04edbe5670 100644\n--- a/reflog.c\n+++ b/reflog.c\n@@ -154,7 +154,7 @@ static int tree_is_complete(const struct object_id *oid)\n \n \tif (!tree->buffer) {\n \t\tenum object_type type;\n-\t\tunsigned long size;\n+\t\tsize_t size;\n \t\tvoid *data = odb_read_object(the_repository->objects, oid,\n \t\t\t\t\t     &type, &size);\n \t\tif (!data) {\ndiff --git a/rerere.c b/rerere.c\nindex 0296700f9f..068321b24f 100644\n--- a/rerere.c\n+++ b/rerere.c\n@@ -990,7 +990,7 @@ static int handle_cache(struct index_state *istate,\n \n \twhile (pos < istate->cache_nr) {\n \t\tenum object_type type;\n-\t\tunsigned long size;\n+\t\tsize_t size;\n \n \t\tce = istate->cache[pos++];\n \t\tif (ce_namelen(ce) != len || memcmp(ce->name, path, len))\ndiff --git a/submodule-config.c b/submodule-config.c\nindex a81897b4e0..f75997402a 100644\n--- a/submodule-config.c\n+++ b/submodule-config.c\n@@ -694,7 +694,7 @@ static const struct submodule *config_from(struct submodule_cache *cache,\n \t\tenum lookup_type lookup_type)\n {\n \tstruct strbuf rev = STRBUF_INIT;\n-\tunsigned long config_size;\n+\tsize_t config_size;\n \tchar *config = NULL;\n \tstruct object_id oid;\n \tenum object_type type;\ndiff --git a/t/helper/test-pack-deltas.c b/t/helper/test-pack-deltas.c\nindex c493b75e02..840797cf0d 100644\n--- a/t/helper/test-pack-deltas.c\n+++ b/t/helper/test-pack-deltas.c\n@@ -48,7 +48,8 @@ static void write_ref_delta(struct hashfile *f,\n \t\t\t    struct object_id *base)\n {\n \tunsigned char header[MAX_PACK_OBJECT_HEADER];\n-\tunsigned long size, base_size, delta_size, compressed_size, hdrlen;\n+\tunsigned long delta_size, compressed_size, hdrlen;\n+\tsize_t size, base_size;\n \tenum object_type type;\n \tvoid *base_buf, *delta_buf;\n \tvoid *buf = odb_read_object(the_repository->objects,\ndiff --git a/t/helper/test-partial-clone.c b/t/helper/test-partial-clone.c\nindex a7aab426d0..87c59108e0 100644\n--- a/t/helper/test-partial-clone.c\n+++ b/t/helper/test-partial-clone.c\n@@ -17,7 +17,7 @@ static void object_info(const char *gitdir, const char *oid_hex)\n {\n \tstruct repository r;\n \tstruct object_id oid;\n-\tunsigned long size;\n+\tsize_t size;\n \tstruct object_info oi = {.sizep = &size};\n \tconst char *p;\n \ndiff --git a/t/unit-tests/u-odb-inmemory.c b/t/unit-tests/u-odb-inmemory.c\nindex 482502ef4b..6844bfc37c 100644\n--- a/t/unit-tests/u-odb-inmemory.c\n+++ b/t/unit-tests/u-odb-inmemory.c\n@@ -20,7 +20,7 @@ static void cl_assert_object_info(struct odb_source_inmemory *source,\n \t\t\t\t  const char *expected_content)\n {\n \tenum object_type actual_type;\n-\tunsigned long actual_size;\n+\tsize_t actual_size;\n \tvoid *actual_content;\n \tstruct object_info oi = {\n \t\t.typep = &actual_type,\ndiff --git a/tag.c b/tag.c\nindex 2f12e51024..1a00ded6eb 100644\n--- a/tag.c\n+++ b/tag.c\n@@ -49,7 +49,7 @@ int gpg_verify_tag(struct repository *r, const struct object_id *oid,\n {\n \tenum object_type type;\n \tchar *buf;\n-\tunsigned long size;\n+\tsize_t size;\n \tint ret;\n \n \ttype = odb_read_object_info(r->objects, oid, NULL);\n@@ -207,7 +207,7 @@ int parse_tag(struct repository *r, struct tag *item)\n {\n \tenum object_type type;\n \tvoid *data;\n-\tunsigned long size;\n+\tsize_t size;\n \tint ret;\n \n \tif (item->object.parsed)\ndiff --git a/tree-walk.c b/tree-walk.c\nindex 7e1b956f27..a67f06b9eb 100644\n--- a/tree-walk.c\n+++ b/tree-walk.c\n@@ -87,7 +87,7 @@ void *fill_tree_descriptor(struct repository *r,\n \t\t\t   struct tree_desc *desc,\n \t\t\t   const struct object_id *oid)\n {\n-\tunsigned long size = 0;\n+\tsize_t size = 0;\n \tvoid *buf = NULL;\n \n \tif (oid) {\n@@ -610,7 +610,7 @@ int get_tree_entry(struct repository *r,\n {\n \tint retval;\n \tvoid *tree;\n-\tunsigned long size;\n+\tsize_t size;\n \tstruct object_id root;\n \n \ttree = odb_read_object_peeled(r->objects, tree_oid, OBJ_TREE, &size, &root);\n@@ -682,7 +682,7 @@ enum get_oid_result get_tree_entry_follow_symlinks(struct repository *r,\n \t\tif (!t.buffer) {\n \t\t\tvoid *tree;\n \t\t\tstruct object_id root;\n-\t\t\tunsigned long size;\n+\t\t\tsize_t size;\n \t\t\ttree = odb_read_object_peeled(r->objects, &current_tree_oid,\n \t\t\t\t\t\t      OBJ_TREE, &size, &root);\n \t\t\tif (!tree)\n@@ -778,6 +778,7 @@ enum get_oid_result get_tree_entry_follow_symlinks(struct repository *r,\n \t\t} else if (S_ISLNK(*mode)) {\n \t\t\t/* Follow a symlink */\n \t\t\tunsigned long link_len;\n+\t\t\tsize_t link_len_st = 0;\n \t\t\tsize_t len;\n \t\t\tchar *contents, *contents_start;\n \t\t\tstruct dir_state *parent;\n@@ -797,7 +798,8 @@ enum get_oid_result get_tree_entry_follow_symlinks(struct repository *r,\n \n \t\t\tcontents = odb_read_object(r->objects,\n \t\t\t\t\t\t   &current_tree_oid, &type,\n-\t\t\t\t\t\t   &link_len);\n+\t\t\t\t\t\t   &link_len_st);\n+\t\t\tlink_len = cast_size_t_to_ulong(link_len_st);\n \n \t\t\tif (!contents)\n \t\t\t\tgoto done;\ndiff --git a/tree.c b/tree.c\nindex d703ab97c8..53f7395e9f 100644\n--- a/tree.c\n+++ b/tree.c\n@@ -188,7 +188,7 @@ int repo_parse_tree_gently(struct repository *r, struct tree *item,\n {\n \t enum object_type type;\n \t void *buffer;\n-\t unsigned long size;\n+\t size_t size;\n \n \tif (item->object.parsed)\n \t\treturn 0;\ndiff --git a/xdiff-interface.c b/xdiff-interface.c\nindex 5ee2b96d0a..db6938689f 100644\n--- a/xdiff-interface.c\n+++ b/xdiff-interface.c\n@@ -179,7 +179,7 @@ int read_mmfile(mmfile_t *ptr, const char *filename)\n void read_mmblob(mmfile_t *ptr, struct object_database *odb,\n \t\t const struct object_id *oid)\n {\n-\tunsigned long size;\n+\tsize_t size;\n \tenum object_type type;\n \n \tif (is_null_oid(oid)) {\n-- \ngitgitgadget\n"},{"id":"544922","messageId":"aibJTHKsmqe_EJHc@pks.im","threadId":"65750","inReplyTo":"1fd7646ca14f7ec392c85fab10255f08d0d79368.1780570273.git.gitgitgadget@gmail.com","subject":"Re: [PATCH 2/7] patch-delta: use size_t for sizes","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2026-06-08T13:53:16Z","receivedAt":"2026-06-08T13:53:27Z","isPatch":true,"body":"On Thu, Jun 04, 2026 at 10:51:07AM +0000, Johannes Schindelin via GitGitGadget wrote:\n> From: Johannes Schindelin <johannes.schindelin@gmx.de>\n> \n> `patch_delta()` takes the source and delta sizes by value and writes\n> back the reconstructed target size through an `unsigned long *`.  That\n> datatype cannot represent a value that exceeds 4 GiB on systems where\n> `unsigned long` is 32-bit (notably 64-bit Windows builds), though, even\n> though the delta encoding itself, the on-disk layout, and the in-memory\n> buffers happily carry such sizes. A `size_t` companion to\n> `get_delta_hdr_size()`, `get_delta_hdr_size_sz()`, was introduced in\n> 17fa077596 (delta, packfile: use size_t for delta header sizes,\n> 2026-05-08) precisely so that `patch_delta()` could be widened without\n> changing the on-the-wire decoding helper's signature.\n> \n> Widen `patch_delta()`'s three size parameters to `size_t` and switch\n> its internal use of `get_delta_hdr_size()` to the `_sz` variant.\n> Then propagate the wider type through the callers.\n\nDoes `get_delta_hdr_size()` have any remaining callers after this patch\nseries? I currently only spot two such callers, and you convert both of\nthem in this patch.\n\nAnd can we reasonably add a test case that exercises this change?\n\n> diff --git a/packfile.c b/packfile.c\n> index 89366abfe3..e202f48837 100644\n> --- a/packfile.c\n> +++ b/packfile.c\n> @@ -1964,10 +1964,8 @@ void *unpack_entry(struct repository *r, struct packed_git *p, off_t obj_offset,\n>  \t\t\t      (uintmax_t)curpos, p->pack_name);\n>  \t\t\tdata = NULL;\n>  \t\t} else {\n> -\t\t\tunsigned long sz;\n>  \t\t\tdata = patch_delta(base, base_size, delta_data,\n> -\t\t\t\t\t   delta_size, &sz);\n> -\t\t\tsize = sz;\n> +\t\t\t\t\t   delta_size, &size);\n\nNice that we get rid of this awkward construct.\n\nPatrick\n"},{"id":"544923","messageId":"aibJVSrKPCfDVXw7@pks.im","threadId":"65750","inReplyTo":"ddb75326cde9695f1eb7bbbe77175424e6b77004.1780570273.git.gitgitgadget@gmail.com","subject":"Re: [PATCH 3/7] pack-objects(check_pack_inflate()): use size_t instead of unsigned long","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2026-06-08T13:53:25Z","receivedAt":"2026-06-08T13:53:37Z","isPatch":true,"body":"On Thu, Jun 04, 2026 at 10:51:08AM +0000, Johannes Schindelin via GitGitGadget wrote:\n> From: Johannes Schindelin <johannes.schindelin@gmx.de>\n> \n> `write_reuse_object()` learned to track its packed-object size as\n> `size_t` in 606c192380 (odb, packfile: use size_t for streaming\n> object sizes, 2026-05-08), but the comparison sink it feeds,\n> `check_pack_inflate()`, still takes the expected decompressed size\n> as `unsigned long`. The call site bridges the mismatch with\n> `cast_size_t_to_ulong()`, which on Windows turns a >4 GiB object\n> into an immediate die().\n> \n> That function only uses `expect` once: as the right-hand side of a\n> `stream.total_out == expect` equality test against zlib's counter.\n> zlib's own `total_out` counter is `uLong` and is therefore still\n> 32-bit-bound on Windows. Widening `expect` to `size_t` cannot fix that,\n> but it is a strict improvement nonetheless: instead of dying outright,\n> an oversized object now simply makes the equality fail and lets\n> `write_reuse_object()` fall back to `write_no_reuse_object()`, which\n> decompresses and re-deflates the content (and which the larger\n> pack-objects widening series targets separately).\n\nHm. I wonder whether it's possible to reset `stream.total_out` on every\niteration and instead have a local `size_t` variable that we use to\ntrack the total number of inflated bytes?\n\nPatrick\n"},{"id":"544924","messageId":"aibJW3h4PaYhOqFb@pks.im","threadId":"65750","inReplyTo":"bdebc36f21d1e2a13bc91d72a3ada1db3f7e184e.1780570273.git.gitgitgadget@gmail.com","subject":"Re: [PATCH 4/7] packfile: widen unpack_entry()'s size out-parameter to size_t","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2026-06-08T13:53:31Z","receivedAt":"2026-06-08T13:53:38Z","isPatch":true,"body":"On Thu, Jun 04, 2026 at 10:51:09AM +0000, Johannes Schindelin via GitGitGadget wrote:\n> diff --git a/builtin/fast-import.c b/builtin/fast-import.c\n> index 82bc6dcc00..3dff898c43 100644\n> --- a/builtin/fast-import.c\n> +++ b/builtin/fast-import.c\n> @@ -1239,6 +1239,8 @@ static void *gfi_unpack_entry(\n>  \tunsigned long *sizep)\n>  {\n>  \tenum object_type type;\n> +\tsize_t size_st = 0;\n> +\tvoid *data;\n>  \tstruct packed_git *p = all_packs[oe->pack_id];\n>  \tif (p == pack_data && p->pack_size < (pack_size + the_hash_algo->rawsz)) {\n>  \t\t/* The object is stored in the packfile we are writing to\n> @@ -1260,7 +1262,10 @@ static void *gfi_unpack_entry(\n>  \t\t */\n>  \t\tp->pack_size = pack_size + the_hash_algo->rawsz;\n>  \t}\n> -\treturn unpack_entry(the_repository, p, oe->idx.offset, &type, sizep);\n> +\tdata = unpack_entry(the_repository, p, oe->idx.offset, &type, &size_st);\n> +\tif (sizep)\n> +\t\t*sizep = cast_size_t_to_ulong(size_st);\n> +\treturn data;\n>  }\n\nNit, please feel free to ignore: do we want to add a NEEDSWORK comment\nhere?\n\nPatrick\n"},{"id":"544925","messageId":"aibJYIPm1gvjNXGV@pks.im","threadId":"65750","inReplyTo":"460d733feeaf2a94fe28d7509cc4128e9c0a7610.1780570273.git.gitgitgadget@gmail.com","subject":"Re: [PATCH 6/7] packfile,delta: drop the `cast_size_t_to_ulong()` wrappers","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2026-06-08T13:53:36Z","receivedAt":"2026-06-08T13:53:41Z","isPatch":true,"body":"On Thu, Jun 04, 2026 at 10:51:11AM +0000, Johannes Schindelin via GitGitGadget wrote:\n> From: Johannes Schindelin <johannes.schindelin@gmx.de>\n> \n> When I started the transition from `unsigned long` to `size_t`, in the\n> interest of keeping the patches reviewable, I introduced these calls to\n> prevent data type narrowing from silently failing to handle large object\n> sizes. I also introduced `*_sz()` variants that would allow most of the\n> callers to keep using that `unsigned long` that the 90s kindly asked to\n> be returned.\n> \n> After the preceding commits, the only places that called the narrow\n> wrappers either no longer exist or already use the `_sz` form\n> internally, so the wrappers just narrow values back through\n> `cast_size_t_to_ulong()` for no reason.\n> \n> Drop them and rename the `_sz` variants back to the natural names.\n\nAha, so you already address my comment I had on one of the preceding\npatches :)\n\nPatrick\n"},{"id":"544926","messageId":"aibJZ8EXoQSD2lsB@pks.im","threadId":"65750","inReplyTo":"f3aeae983ac8b281d6ba54299961e19d16699c94.1780570273.git.gitgitgadget@gmail.com","subject":"Re: [PATCH 7/7] odb: use size_t for object_info.sizep and the size APIs","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2026-06-08T13:53:43Z","receivedAt":"2026-06-08T13:53:48Z","isPatch":true,"body":"On Thu, Jun 04, 2026 at 10:51:12AM +0000, Johannes Schindelin via GitGitGadget wrote:\n> diff --git a/builtin/cat-file.c b/builtin/cat-file.c\n> index fa45f774d7..fa6e396ddc 100644\n> --- a/builtin/cat-file.c\n> +++ b/builtin/cat-file.c\n> @@ -120,7 +120,7 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name)\n>  \tstruct object_id oid;\n>  \tenum object_type type;\n>  \tchar *buf;\n> -\tunsigned long size;\n> +\tsize_t size;\n>  \tstruct object_context obj_context = {0};\n>  \tstruct object_info oi = OBJECT_INFO_INIT;\n>  \tunsigned flags = OBJECT_INFO_LOOKUP_REPLACE;\n> @@ -166,7 +166,7 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name)\n>  \t\tif (use_mailmap && (type == OBJ_COMMIT || type == OBJ_TAG)) {\n>  \t\t\tsize_t s = size;\n>  \t\t\tbuf = replace_idents_using_mailmap(buf, &s);\n> -\t\t\tsize = cast_size_t_to_ulong(s);\n> +\t\t\tsize = s;\n>  \t\t}\n>  \n>  \t\tprintf(\"%\"PRIuMAX\"\\n\", (uintmax_t)size);\n\nCan't we drop this local variable completely and instead supply `&size`\ndirectly?\n\n> @@ -219,7 +225,7 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name)\n>  \t\tif (use_mailmap) {\n>  \t\t\tsize_t s = size;\n>  \t\t\tbuf = replace_idents_using_mailmap(buf, &s);\n> -\t\t\tsize = cast_size_t_to_ulong(s);\n> +\t\t\tsize = s;\n>  \t\t}\n>  \n>  \t\t/* otherwise just spit out the data */\n> @@ -266,7 +272,7 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name)\n>  \t\tif (use_mailmap) {\n>  \t\t\tsize_t s = size;\n>  \t\t\tbuf = replace_idents_using_mailmap(buf, &s);\n> -\t\t\tsize = cast_size_t_to_ulong(s);\n> +\t\t\tsize = s;\n>  \t\t}\n>  \t\tbreak;\n>  \t}\n> @@ -446,7 +455,7 @@ static void print_object_or_die(struct batch_options *opt, struct expand_data *d\n>  \t\tif (use_mailmap) {\n>  \t\t\tsize_t s = size;\n>  \t\t\tcontents = replace_idents_using_mailmap(contents, &s);\n> -\t\t\tsize = cast_size_t_to_ulong(s);\n> +\t\t\tsize = s;\n>  \t\t}\n>  \n>  \t\tif (type != data->type)\n\nLikewise for these three instances.\n\n> @@ -555,7 +564,7 @@ static void batch_object_write(const char *obj_name,\n>  \t\t\tif (!buf)\n>  \t\t\t\tdie(_(\"unable to read %s\"), oid_to_hex(&data->oid));\n>  \t\t\tbuf = replace_idents_using_mailmap(buf, &s);\n> -\t\t\tdata->size = cast_size_t_to_ulong(s);\n> +\t\t\tdata->size = s;\n>  \n>  \t\t\tfree(buf);\n>  \t\t}\n\nAnd I think this site here can be adapted, as well.\n\n> diff --git a/diff.c b/diff.c\n> index 5a584fa1d5..816b89dc6c 100644\n> --- a/diff.c\n> +++ b/diff.c\n> @@ -4594,8 +4594,9 @@ int diff_populate_filespec(struct repository *r,\n>  \t\t}\n>  \t}\n>  \telse {\n> +\t\tsize_t size_st = 0;\n>  \t\tstruct object_info info = {\n> -\t\t\t.sizep = &s->size\n> +\t\t\t.sizep = &size_st\n>  \t\t};\n>  \n>  \t\tif (!(size_only || check_binary))\n> @@ -4617,6 +4618,7 @@ int diff_populate_filespec(struct repository *r,\n>  \t\t\tdie(\"unable to read %s\", oid_to_hex(&s->oid));\n>  \n>  object_read:\n> +\t\ts->size = cast_size_t_to_ulong(size_st);\n>  \t\tif (size_only || check_binary) {\n>  \t\t\tif (size_only)\n>  \t\t\t\treturn 0;\n> @@ -4631,6 +4633,7 @@ object_read:\n>  \t\t\tif (odb_read_object_info_extended(r->objects, &s->oid, &info,\n>  \t\t\t\t\t\t\t  OBJECT_INFO_LOOKUP_REPLACE))\n>  \t\t\t\tdie(\"unable to read %s\", oid_to_hex(&s->oid));\n> +\t\t\ts->size = cast_size_t_to_ulong(size_st);\n>  \t\t}\n>  \t\ts->should_free = 1;\n>  \t}\n\nThe flow in this function is quite weird if you ask me, but that's a\npreexisting issue. This does look correct to me, even if it's awkward.\n\nPatrick\n"},{"id":"545532","messageId":"03cc2127-7686-5d71-0e8e-aa2fccb78820@gmx.de","threadId":"65750","inReplyTo":"aibJTHKsmqe_EJHc@pks.im","subject":"Re: [PATCH 2/7] patch-delta: use size_t for sizes","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2026-06-15T09:29:32Z","receivedAt":"2026-06-15T09:29:37Z","isPatch":true,"body":"Hi Patrick,\n\nOn Mon, 15 Jun 2026, Patrick Steinhardt wrote:\n\n> On Thu, Jun 04, 2026 at 10:51:07AM +0000, Johannes Schindelin via GitGitGadget wrote:\n> > From: Johannes Schindelin <johannes.schindelin@gmx.de>\n> > \n> > `patch_delta()` takes the source and delta sizes by value and writes\n> > back the reconstructed target size through an `unsigned long *`.  That\n> > datatype cannot represent a value that exceeds 4 GiB on systems where\n> > `unsigned long` is 32-bit (notably 64-bit Windows builds), though, even\n> > though the delta encoding itself, the on-disk layout, and the in-memory\n> > buffers happily carry such sizes. A `size_t` companion to\n> > `get_delta_hdr_size()`, `get_delta_hdr_size_sz()`, was introduced in\n> > 17fa077596 (delta, packfile: use size_t for delta header sizes,\n> > 2026-05-08) precisely so that `patch_delta()` could be widened without\n> > changing the on-the-wire decoding helper's signature.\n> > \n> > Widen `patch_delta()`'s three size parameters to `size_t` and switch\n> > its internal use of `get_delta_hdr_size()` to the `_sz` variant.\n> > Then propagate the wider type through the callers.\n> \n> Does `get_delta_hdr_size()` have any remaining callers after this patch\n> series? I currently only spot two such callers, and you convert both of\n> them in this patch.\n\nAs you noticed later on in the review: No, there are no such callers left,\nand the `_sz` variant gets renamed, concluding the incremental migration\nof that function from `unsigned long` to `size_t`.\n\n> And can we reasonably add a test case that exercises this change?\n\nNot reasonably, no. This would require constructing another artificial\n_large_ object, this time with an unpacked Git object with a size >=4GB\nthat needs to be transmogrified into a different object.\n\nBetter leave the verification of this patch to static analysis (GCC or\nClang have become quite good at spotting things like this; Coverity would\nbe, too, if it ever comes back up from its \"upgrades to the Scan servers\",\nhttps://web.archive.org/web/20260516152422/https://scan.coverity.com/\nseems to be the start date of this update).\n\n> \n> > diff --git a/packfile.c b/packfile.c\n> > index 89366abfe3..e202f48837 100644\n> > --- a/packfile.c\n> > +++ b/packfile.c\n> > @@ -1964,10 +1964,8 @@ void *unpack_entry(struct repository *r, struct packed_git *p, off_t obj_offset,\n> >  \t\t\t      (uintmax_t)curpos, p->pack_name);\n> >  \t\t\tdata = NULL;\n> >  \t\t} else {\n> > -\t\t\tunsigned long sz;\n> >  \t\t\tdata = patch_delta(base, base_size, delta_data,\n> > -\t\t\t\t\t   delta_size, &sz);\n> > -\t\t\tsize = sz;\n> > +\t\t\t\t\t   delta_size, &size);\n> \n> Nice that we get rid of this awkward construct.\n\nAwkward, but necessary to allow for an incremental, reviewable conversion\n;-)\n\nCiao,\nJohannes\n"},{"id":"545533","messageId":"3caf123b-d1ad-5e49-7a95-027569cf62a4@gmx.de","threadId":"65750","inReplyTo":"aibJVSrKPCfDVXw7@pks.im","subject":"Re: [PATCH 3/7] pack-objects(check_pack_inflate()): use size_t instead of unsigned long","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2026-06-15T09:29:37Z","receivedAt":"2026-06-15T09:29:43Z","isPatch":true,"body":"Hi Patrick,\n\nOn Mon, 15 Jun 2026, Patrick Steinhardt wrote:\n\n> On Thu, Jun 04, 2026 at 10:51:08AM +0000, Johannes Schindelin via GitGitGadget wrote:\n> > From: Johannes Schindelin <johannes.schindelin@gmx.de>\n> > \n> > `write_reuse_object()` learned to track its packed-object size as\n> > `size_t` in 606c192380 (odb, packfile: use size_t for streaming\n> > object sizes, 2026-05-08), but the comparison sink it feeds,\n> > `check_pack_inflate()`, still takes the expected decompressed size\n> > as `unsigned long`. The call site bridges the mismatch with\n> > `cast_size_t_to_ulong()`, which on Windows turns a >4 GiB object\n> > into an immediate die().\n> > \n> > That function only uses `expect` once: as the right-hand side of a\n> > `stream.total_out == expect` equality test against zlib's counter.\n> > zlib's own `total_out` counter is `uLong` and is therefore still\n> > 32-bit-bound on Windows. Widening `expect` to `size_t` cannot fix that,\n> > but it is a strict improvement nonetheless: instead of dying outright,\n> > an oversized object now simply makes the equality fail and lets\n> > `write_reuse_object()` fall back to `write_no_reuse_object()`, which\n> > decompresses and re-deflates the content (and which the larger\n> > pack-objects widening series targets separately).\n> \n> Hm. I wonder whether it's possible to reset `stream.total_out` on every\n> iteration and instead have a local `size_t` variable that we use to\n> track the total number of inflated bytes?\n\nPossible? Yes. Appropriate? Unlikely. We would now pretend to have\ninflated less bytes, _just_ to appease a data type limitation that we\nalready worked around in d05d666977 (git-zlib: handle data streams larger\nthan 4GB, 2026-05-08).\n\nCiao,\nJohannes\n"},{"id":"545534","messageId":"5e87910d-d8bb-76f1-d3c2-0e3d9e5d7814@gmx.de","threadId":"65750","inReplyTo":"aibJW3h4PaYhOqFb@pks.im","subject":"Re: [PATCH 4/7] packfile: widen unpack_entry()'s size out-parameter to size_t","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2026-06-15T09:29:43Z","receivedAt":"2026-06-15T09:29:46Z","isPatch":true,"body":"Hi Patrick,\n\nOn Mon, 15 Jun 2026, Patrick Steinhardt wrote:\n\n> On Thu, Jun 04, 2026 at 10:51:09AM +0000, Johannes Schindelin via GitGitGadget wrote:\n> > diff --git a/builtin/fast-import.c b/builtin/fast-import.c\n> > index 82bc6dcc00..3dff898c43 100644\n> > --- a/builtin/fast-import.c\n> > +++ b/builtin/fast-import.c\n> > @@ -1239,6 +1239,8 @@ static void *gfi_unpack_entry(\n> >  \tunsigned long *sizep)\n> >  {\n> >  \tenum object_type type;\n> > +\tsize_t size_st = 0;\n> > +\tvoid *data;\n> >  \tstruct packed_git *p = all_packs[oe->pack_id];\n> >  \tif (p == pack_data && p->pack_size < (pack_size + the_hash_algo->rawsz)) {\n> >  \t\t/* The object is stored in the packfile we are writing to\n> > @@ -1260,7 +1262,10 @@ static void *gfi_unpack_entry(\n> >  \t\t */\n> >  \t\tp->pack_size = pack_size + the_hash_algo->rawsz;\n> >  \t}\n> > -\treturn unpack_entry(the_repository, p, oe->idx.offset, &type, sizep);\n> > +\tdata = unpack_entry(the_repository, p, oe->idx.offset, &type, &size_st);\n> > +\tif (sizep)\n> > +\t\t*sizep = cast_size_t_to_ulong(size_st);\n> > +\treturn data;\n> >  }\n> \n> Nit, please feel free to ignore: do we want to add a NEEDSWORK comment\n> here?\n\nHehe... My mind translates the `cast_size_t_to_ulong()` function to\n\"NEEDSWORK!\" already ;-)\n\nCiao,\nJohannes\n"},{"id":"545535","messageId":"d82abb94-1720-ba15-15b6-e1a9ac28b0aa@gmx.de","threadId":"65750","inReplyTo":"aibJZ8EXoQSD2lsB@pks.im","subject":"Re: [PATCH 7/7] odb: use size_t for object_info.sizep and the size APIs","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2026-06-15T09:29:53Z","receivedAt":"2026-06-15T09:29:59Z","isPatch":true,"body":"Hi Patrick,\n\nOn Mon, 15 Jun 2026, Patrick Steinhardt wrote:\n\n> On Thu, Jun 04, 2026 at 10:51:12AM +0000, Johannes Schindelin via GitGitGadget wrote:\n> > diff --git a/builtin/cat-file.c b/builtin/cat-file.c\n> > index fa45f774d7..fa6e396ddc 100644\n> > --- a/builtin/cat-file.c\n> > +++ b/builtin/cat-file.c\n> > @@ -120,7 +120,7 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name)\n> >  \tstruct object_id oid;\n> >  \tenum object_type type;\n> >  \tchar *buf;\n> > -\tunsigned long size;\n> > +\tsize_t size;\n> >  \tstruct object_context obj_context = {0};\n> >  \tstruct object_info oi = OBJECT_INFO_INIT;\n> >  \tunsigned flags = OBJECT_INFO_LOOKUP_REPLACE;\n> > @@ -166,7 +166,7 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name)\n> >  \t\tif (use_mailmap && (type == OBJ_COMMIT || type == OBJ_TAG)) {\n> >  \t\t\tsize_t s = size;\n> >  \t\t\tbuf = replace_idents_using_mailmap(buf, &s);\n> > -\t\t\tsize = cast_size_t_to_ulong(s);\n> > +\t\t\tsize = s;\n> >  \t\t}\n> >  \n> >  \t\tprintf(\"%\"PRIuMAX\"\\n\", (uintmax_t)size);\n> \n> Can't we drop this local variable completely and instead supply `&size`\n> directly?\n\nWell spotted!\n\n> > @@ -219,7 +225,7 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name)\n> >  \t\tif (use_mailmap) {\n> >  \t\t\tsize_t s = size;\n> >  \t\t\tbuf = replace_idents_using_mailmap(buf, &s);\n> > -\t\t\tsize = cast_size_t_to_ulong(s);\n> > +\t\t\tsize = s;\n> >  \t\t}\n> >  \n> >  \t\t/* otherwise just spit out the data */\n> > @@ -266,7 +272,7 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name)\n> >  \t\tif (use_mailmap) {\n> >  \t\t\tsize_t s = size;\n> >  \t\t\tbuf = replace_idents_using_mailmap(buf, &s);\n> > -\t\t\tsize = cast_size_t_to_ulong(s);\n> > +\t\t\tsize = s;\n> >  \t\t}\n> >  \t\tbreak;\n> >  \t}\n> > @@ -446,7 +455,7 @@ static void print_object_or_die(struct batch_options *opt, struct expand_data *d\n> >  \t\tif (use_mailmap) {\n> >  \t\t\tsize_t s = size;\n> >  \t\t\tcontents = replace_idents_using_mailmap(contents, &s);\n> > -\t\t\tsize = cast_size_t_to_ulong(s);\n> > +\t\t\tsize = s;\n> >  \t\t}\n> >  \n> >  \t\tif (type != data->type)\n> \n> Likewise for these three instances.\n\nI totally agree.\n\n> > @@ -555,7 +564,7 @@ static void batch_object_write(const char *obj_name,\n> >  \t\t\tif (!buf)\n> >  \t\t\t\tdie(_(\"unable to read %s\"), oid_to_hex(&data->oid));\n> >  \t\t\tbuf = replace_idents_using_mailmap(buf, &s);\n> > -\t\t\tdata->size = cast_size_t_to_ulong(s);\n> > +\t\t\tdata->size = s;\n> >  \n> >  \t\t\tfree(buf);\n> >  \t\t}\n> \n> And I think this site here can be adapted, as well.\n\nIndeed!\n\n> > diff --git a/diff.c b/diff.c\n> > index 5a584fa1d5..816b89dc6c 100644\n> > --- a/diff.c\n> > +++ b/diff.c\n> > @@ -4594,8 +4594,9 @@ int diff_populate_filespec(struct repository *r,\n> >  \t\t}\n> >  \t}\n> >  \telse {\n> > +\t\tsize_t size_st = 0;\n> >  \t\tstruct object_info info = {\n> > -\t\t\t.sizep = &s->size\n> > +\t\t\t.sizep = &size_st\n> >  \t\t};\n> >  \n> >  \t\tif (!(size_only || check_binary))\n> > @@ -4617,6 +4618,7 @@ int diff_populate_filespec(struct repository *r,\n> >  \t\t\tdie(\"unable to read %s\", oid_to_hex(&s->oid));\n> >  \n> >  object_read:\n> > +\t\ts->size = cast_size_t_to_ulong(size_st);\n> >  \t\tif (size_only || check_binary) {\n> >  \t\t\tif (size_only)\n> >  \t\t\t\treturn 0;\n> > @@ -4631,6 +4633,7 @@ object_read:\n> >  \t\t\tif (odb_read_object_info_extended(r->objects, &s->oid, &info,\n> >  \t\t\t\t\t\t\t  OBJECT_INFO_LOOKUP_REPLACE))\n> >  \t\t\t\tdie(\"unable to read %s\", oid_to_hex(&s->oid));\n> > +\t\t\ts->size = cast_size_t_to_ulong(size_st);\n> >  \t\t}\n> >  \t\ts->should_free = 1;\n> >  \t}\n> \n> The flow in this function is quite weird if you ask me, but that's a\n> preexisting issue. This does look correct to me, even if it's awkward.\n\nYes, on all four accounts.\n\nCiao,\nJohannes\n"},{"id":"545541","messageId":"pull.2137.v2.git.1781524349.gitgitgadget@gmail.com","threadId":"65750","inReplyTo":"pull.2137.git.1780570272.gitgitgadget@gmail.com","subject":"[PATCH v2 0/7] More work supporting objects larger than 4GB on Windows","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2026-06-15T11:52:22Z","receivedAt":"2026-06-15T11:52:32Z","isPatch":true,"body":"This patch series tries to address the problems pointed out by the expensive\ntests that now run in CI: t5608 and t7508 verify various aspects about\nobjects larger than 4GB, which Git does not currently handle correctly when\nrun on a platform where size_t is 64-bit and unsigned long is 32-bit.\n\nChanges vs v1:\n\n * Rebased onto master, which merged ps/odb-source-loose (with which these\n   patches previously conflicted rather badly).\n * Removed superfluous size_t s variables (thanks, Patrick!).\n\nJohannes Schindelin (7):\n  compat/msvc: use _chsize_s for ftruncate\n  patch-delta: use size_t for sizes\n  pack-objects(check_pack_inflate()): use size_t instead of unsigned\n    long\n  packfile: widen unpack_entry()'s size out-parameter to size_t\n  pack-objects: use size_t for in-core object sizes\n  packfile,delta: drop the `cast_size_t_to_ulong()` wrappers\n  odb: use size_t for object_info.sizep and the size APIs\n\n apply.c                       |  8 ++--\n archive.c                     |  4 +-\n attr.c                        |  2 +-\n bisect.c                      |  2 +-\n blame.c                       | 15 +++++--\n builtin/cat-file.c            | 61 ++++++++++++++---------------\n builtin/difftool.c            |  2 +-\n builtin/fast-export.c         |  7 +++-\n builtin/fast-import.c         | 29 ++++++++++----\n builtin/fsck.c                |  2 +-\n builtin/grep.c                | 12 +++---\n builtin/index-pack.c          | 10 ++---\n builtin/log.c                 |  2 +-\n builtin/ls-files.c            |  2 +-\n builtin/ls-tree.c             |  4 +-\n builtin/merge-tree.c          |  6 +--\n builtin/mktag.c               |  2 +-\n builtin/notes.c               |  6 +--\n builtin/pack-objects.c        | 73 +++++++++++++++++++++--------------\n builtin/repo.c                |  4 +-\n builtin/tag.c                 |  4 +-\n builtin/unpack-file.c         |  2 +-\n builtin/unpack-objects.c      |  8 ++--\n bundle.c                      |  2 +-\n combine-diff.c                |  4 +-\n commit.c                      | 10 ++---\n compat/msvc-posix.h           | 24 +++++++++++-\n config.c                      |  2 +-\n delta.h                       | 20 +++-------\n diff.c                        |  5 ++-\n dir.c                         |  2 +-\n entry.c                       |  4 +-\n fmt-merge-msg.c               |  4 +-\n fsck.c                        |  2 +-\n grep.c                        |  4 +-\n http-push.c                   |  2 +-\n list-objects-filter.c         |  2 +-\n mailmap.c                     |  2 +-\n match-trees.c                 |  4 +-\n merge-blobs.c                 |  6 +--\n merge-blobs.h                 |  2 +-\n merge-ort.c                   |  2 +-\n notes-cache.c                 |  2 +-\n notes-merge.c                 |  2 +-\n notes.c                       |  8 ++--\n object-file.c                 |  6 +--\n object.c                      |  2 +-\n odb.c                         | 12 +++---\n odb.h                         | 10 ++---\n odb/source-loose.c            | 12 +-----\n odb/streaming.c               | 13 +------\n pack-bitmap.c                 |  4 +-\n pack-check.c                  |  5 +--\n pack-objects.h                |  2 +-\n packfile.c                    | 54 ++++++++++----------------\n packfile.h                    |  5 ++-\n patch-delta.c                 |  8 ++--\n path-walk.c                   |  2 +-\n protocol-caps.c               |  5 ++-\n read-cache.c                  |  6 +--\n ref-filter.c                  |  2 +-\n reflog.c                      |  2 +-\n rerere.c                      |  2 +-\n submodule-config.c            |  2 +-\n t/helper/test-delta.c         | 10 +++--\n t/helper/test-pack-deltas.c   |  3 +-\n t/helper/test-partial-clone.c |  2 +-\n t/unit-tests/u-odb-inmemory.c |  2 +-\n tag.c                         |  4 +-\n tree-walk.c                   | 10 +++--\n tree.c                        |  2 +-\n xdiff-interface.c             |  2 +-\n 72 files changed, 300 insertions(+), 271 deletions(-)\n\n\nbase-commit: ea97ad8d017de0c9037451a78008a0fd60abea0c\nPublished-As: https://github.com/gitgitgadget/git/releases/tag/pr-2137%2Fdscho%2Fobjects-larger-than-4gb-on-windows-pt2-v2\nFetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-2137/dscho/objects-larger-than-4gb-on-windows-pt2-v2\nPull-Request: https://github.com/gitgitgadget/git/pull/2137\n\nRange-diff vs v1:\n\n 1:  de9fc5c455 = 1:  531bca775c compat/msvc: use _chsize_s for ftruncate\n 2:  1fd7646ca1 = 2:  66a642c39e patch-delta: use size_t for sizes\n 3:  ddb75326cd = 3:  271a5299e3 pack-objects(check_pack_inflate()): use size_t instead of unsigned long\n 4:  bdebc36f21 = 4:  5c329535df packfile: widen unpack_entry()'s size out-parameter to size_t\n 5:  68750ba2d1 = 5:  01b9209b26 pack-objects: use size_t for in-core object sizes\n 6:  460d733fee = 6:  12c142f8ab packfile,delta: drop the `cast_size_t_to_ulong()` wrappers\n 7:  f3aeae983a ! 7:  37d030d867 odb: use size_t for object_info.sizep and the size APIs\n     @@ builtin/cat-file.c: static int cat_one_file(int opt, const char *exp_type, const\n       \tstruct object_info oi = OBJECT_INFO_INIT;\n       \tunsigned flags = OBJECT_INFO_LOOKUP_REPLACE;\n      @@ builtin/cat-file.c: static int cat_one_file(int opt, const char *exp_type, const char *obj_name)\n     - \t\tif (use_mailmap && (type == OBJ_COMMIT || type == OBJ_TAG)) {\n     - \t\t\tsize_t s = size;\n     - \t\t\tbuf = replace_idents_using_mailmap(buf, &s);\n     + \t\tif (odb_read_object_info_extended(the_repository->objects, &oid, &oi, flags) < 0)\n     + \t\t\tdie(\"git cat-file: could not get object info\");\n     + \n     +-\t\tif (use_mailmap && (type == OBJ_COMMIT || type == OBJ_TAG)) {\n     +-\t\t\tsize_t s = size;\n     +-\t\t\tbuf = replace_idents_using_mailmap(buf, &s);\n      -\t\t\tsize = cast_size_t_to_ulong(s);\n     -+\t\t\tsize = s;\n     - \t\t}\n     +-\t\t}\n     ++\t\tif (use_mailmap && (type == OBJ_COMMIT || type == OBJ_TAG))\n     ++\t\t\tbuf = replace_idents_using_mailmap(buf, &size);\n       \n       \t\tprintf(\"%\"PRIuMAX\"\\n\", (uintmax_t)size);\n     + \t\tret = 0;\n      @@ builtin/cat-file.c: static int cat_one_file(int opt, const char *exp_type, const char *obj_name)\n       \t\tbreak;\n       \n     @@ builtin/cat-file.c: static int cat_one_file(int opt, const char *exp_type, const\n       \n       \tcase 'p':\n      @@ builtin/cat-file.c: static int cat_one_file(int opt, const char *exp_type, const char *obj_name)\n     - \t\tif (use_mailmap) {\n     - \t\t\tsize_t s = size;\n     - \t\t\tbuf = replace_idents_using_mailmap(buf, &s);\n     + \t\tif (!buf)\n     + \t\t\tdie(\"Cannot read object %s\", obj_name);\n     + \n     +-\t\tif (use_mailmap) {\n     +-\t\t\tsize_t s = size;\n     +-\t\t\tbuf = replace_idents_using_mailmap(buf, &s);\n      -\t\t\tsize = cast_size_t_to_ulong(s);\n     -+\t\t\tsize = s;\n     - \t\t}\n     +-\t\t}\n     ++\t\tif (use_mailmap)\n     ++\t\t\tbuf = replace_idents_using_mailmap(buf, &size);\n       \n       \t\t/* otherwise just spit out the data */\n     + \t\tbreak;\n      @@ builtin/cat-file.c: static int cat_one_file(int opt, const char *exp_type, const char *obj_name)\n     - \t\tif (use_mailmap) {\n     - \t\t\tsize_t s = size;\n     - \t\t\tbuf = replace_idents_using_mailmap(buf, &s);\n     + \t\tbuf = odb_read_object_peeled(the_repository->objects, &oid,\n     + \t\t\t\t\t     exp_type_id, &size, NULL);\n     + \n     +-\t\tif (use_mailmap) {\n     +-\t\t\tsize_t s = size;\n     +-\t\t\tbuf = replace_idents_using_mailmap(buf, &s);\n      -\t\t\tsize = cast_size_t_to_ulong(s);\n     -+\t\t\tsize = s;\n     - \t\t}\n     +-\t\t}\n     ++\t\tif (use_mailmap)\n     ++\t\t\tbuf = replace_idents_using_mailmap(buf, &size);\n       \t\tbreak;\n       \t}\n     + \tdefault:\n      @@ builtin/cat-file.c: cleanup:\n       struct expand_data {\n       \tstruct object_id oid;\n     @@ builtin/cat-file.c: static void print_object_or_die(struct batch_options *opt, s\n       \n       \t\tcontents = odb_read_object(the_repository->objects, oid,\n      @@ builtin/cat-file.c: static void print_object_or_die(struct batch_options *opt, struct expand_data *d\n     - \t\tif (use_mailmap) {\n     - \t\t\tsize_t s = size;\n     - \t\t\tcontents = replace_idents_using_mailmap(contents, &s);\n     + \t\tif (!contents)\n     + \t\t\tdie(\"object %s disappeared\", oid_to_hex(oid));\n     + \n     +-\t\tif (use_mailmap) {\n     +-\t\t\tsize_t s = size;\n     +-\t\t\tcontents = replace_idents_using_mailmap(contents, &s);\n      -\t\t\tsize = cast_size_t_to_ulong(s);\n     -+\t\t\tsize = s;\n     - \t\t}\n     +-\t\t}\n     ++\t\tif (use_mailmap)\n     ++\t\t\tcontents = replace_idents_using_mailmap(contents, &size);\n       \n       \t\tif (type != data->type)\n     + \t\t\tdie(\"object %s changed type!?\", oid_to_hex(oid));\n      @@ builtin/cat-file.c: static void batch_object_write(const char *obj_name,\n     + \t\t}\n     + \n     + \t\tif (use_mailmap && (data->type == OBJ_COMMIT || data->type == OBJ_TAG)) {\n     +-\t\t\tsize_t s = data->size;\n     + \t\t\tchar *buf = NULL;\n     + \n     + \t\t\tbuf = odb_read_object(the_repository->objects, &data->oid,\n     + \t\t\t\t\t      &data->type, &data->size);\n       \t\t\tif (!buf)\n       \t\t\t\tdie(_(\"unable to read %s\"), oid_to_hex(&data->oid));\n     - \t\t\tbuf = replace_idents_using_mailmap(buf, &s);\n     +-\t\t\tbuf = replace_idents_using_mailmap(buf, &s);\n      -\t\t\tdata->size = cast_size_t_to_ulong(s);\n     -+\t\t\tdata->size = s;\n     ++\t\t\tbuf = replace_idents_using_mailmap(buf, &data->size);\n       \n       \t\t\tfree(buf);\n       \t\t}\n     @@ builtin/log.c: static int show_blob_object(const struct object_id *oid, struct r\n      \n       ## builtin/ls-files.c ##\n      @@ builtin/ls-files.c: static void expand_objectsize(struct repository *repo, struct strbuf *line,\n     - \t\t\t      const enum object_type type, unsigned int padded)\n     - {\n     + \tsize_t len;\n     + \n       \tif (type == OBJ_BLOB) {\n      -\t\tunsigned long size;\n      +\t\tsize_t size;\n     @@ builtin/ls-files.c: static void expand_objectsize(struct repository *repo, struc\n      \n       ## builtin/ls-tree.c ##\n      @@ builtin/ls-tree.c: static void expand_objectsize(struct strbuf *line, const struct object_id *oid,\n     - \t\t\t      const enum object_type type, unsigned int padded)\n     - {\n     + \tsize_t len;\n     + \n       \tif (type == OBJ_BLOB) {\n      -\t\tunsigned long size;\n      +\t\tsize_t size;\n     @@ notes.c: static void format_note(struct notes_tree *t, const struct object_id *o\n       \tif (!t)\n      \n       ## object-file.c ##\n     -@@ object-file.c: static int parse_loose_header(const char *hdr, struct object_info *oi)\n     +@@ object-file.c: int parse_loose_header(const char *hdr, struct object_info *oi)\n       \t}\n       \n       \tif (oi->sizep)\n     @@ object-file.c: static int parse_loose_header(const char *hdr, struct object_info\n       \n       \t/*\n       \t * The length must be followed by a zero byte\n     -@@ object-file.c: static int read_object_info_from_path(struct odb_source *source,\n     - \tvoid *map = NULL;\n     - \tgit_zstream stream, *stream_to_end = NULL;\n     - \tchar hdr[MAX_HEADER_LEN];\n     --\tunsigned long size_scratch;\n     -+\tsize_t size_scratch;\n     - \tenum object_type type_scratch;\n     - \tstruct stat st;\n     - \n      @@ object-file.c: int force_object_loose(struct odb_source *source,\n     - {\n     + \tstruct odb_source_files *files = odb_source_files_downcast(source);\n       \tconst struct git_hash_algo *compat = source->odb->repo->compat_hash_algo;\n       \tvoid *buf;\n      -\tunsigned long len;\n     @@ object-file.c: int read_loose_object(struct repository *repo,\n       \n       \tfd = git_open(path);\n       \tif (fd >= 0)\n     -@@ object-file.c: int odb_source_loose_read_object_stream(struct odb_read_stream **out,\n     - \tstruct object_info oi = OBJECT_INFO_INIT;\n     - \tstruct odb_loose_read_stream *st;\n     - \tunsigned long mapsize;\n     --\tunsigned long size_ul;\n     - \tvoid *mapped;\n     - \n     - \tmapped = odb_source_loose_map_object(source, oid, &mapsize);\n     -@@ object-file.c: int odb_source_loose_read_object_stream(struct odb_read_stream **out,\n     - \t\tgoto error;\n     - \t}\n     - \n     --\t/*\n     --\t * object_info.sizep is unsigned long* (32-bit on Windows), but\n     --\t * st->base.size is size_t (64-bit). Use temporary variable.\n     --\t * Note: loose objects >4GB would still truncate here, but such\n     --\t * large loose objects are uncommon (they'd normally be packed).\n     --\t */\n     --\toi.sizep = &size_ul;\n     -+\toi.sizep = &st->base.size;\n     - \toi.typep = &st->base.type;\n     - \n     - \tif (parse_loose_header(st->hdr, &oi) < 0 || st->base.type < 0)\n     - \t\tgoto error;\n     --\tst->base.size = size_ul;\n     - \n     - \tst->mapped = mapped;\n     - \tst->mapsize = mapsize;\n      \n       ## object.c ##\n      @@ object.c: struct object *parse_object_with_flags(struct repository *r,\n     @@ odb.h: int odb_read_object_info_extended(struct object_database *odb,\n       enum odb_has_object_flags {\n       \t/* Retry packed storage after checking packed and loose storage */\n      \n     + ## odb/source-loose.c ##\n     +@@ odb/source-loose.c: static int read_object_info_from_path(struct odb_source_loose *loose,\n     + \tvoid *map = NULL;\n     + \tgit_zstream stream, *stream_to_end = NULL;\n     + \tchar hdr[MAX_HEADER_LEN];\n     +-\tunsigned long size_scratch;\n     ++\tsize_t size_scratch;\n     + \tenum object_type type_scratch;\n     + \tstruct stat st;\n     + \n     +@@ odb/source-loose.c: static int odb_source_loose_read_object_stream(struct odb_read_stream **out,\n     + \tstruct object_info oi = OBJECT_INFO_INIT;\n     + \tstruct odb_loose_read_stream *st;\n     + \tunsigned long mapsize;\n     +-\tunsigned long size_ul;\n     + \tvoid *mapped;\n     + \n     + \tmapped = odb_source_loose_map_object(loose, oid, &mapsize);\n     +@@ odb/source-loose.c: static int odb_source_loose_read_object_stream(struct odb_read_stream **out,\n     + \t\tgoto error;\n     + \t}\n     + \n     +-\t/*\n     +-\t * object_info.sizep is unsigned long* (32-bit on Windows), but\n     +-\t * st->base.size is size_t (64-bit). Use temporary variable.\n     +-\t * Note: loose objects >4GB would still truncate here, but such\n     +-\t * large loose objects are uncommon (they'd normally be packed).\n     +-\t */\n     +-\toi.sizep = &size_ul;\n     ++\toi.sizep = &st->base.size;\n     + \toi.typep = &st->base.type;\n     + \n     + \tif (parse_loose_header(st->hdr, &oi) < 0 || st->base.type < 0)\n     + \t\tgoto error;\n     +-\tst->base.size = size_ul;\n     + \n     + \tst->mapped = mapped;\n     + \tst->mapsize = mapsize;\n     +\n       ## odb/streaming.c ##\n      @@ odb/streaming.c: static int open_istream_incore(struct odb_read_stream **out,\n       \t\t.base.read = read_istream_incore,\n\n-- \ngitgitgadget\n"},{"id":"545542","messageId":"531bca775cf395dfc7547483722156e16a6ed987.1781524349.git.gitgitgadget@gmail.com","threadId":"65750","inReplyTo":"pull.2137.v2.git.1781524349.gitgitgadget@gmail.com","subject":"[PATCH v2 1/7] compat/msvc: use _chsize_s for ftruncate","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2026-06-15T11:52:23Z","receivedAt":"2026-06-15T11:52:33Z","isPatch":true,"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nOn Windows, `unsigned long` and `long` are 32 bits even on 64-bit\nbuilds. The MSVC compatibility header has shimmed `ftruncate()` with\n\n\t#define ftruncate _chsize\n\never since `compat/msvc-posix.h` was introduced. `_chsize()` takes a\n32-bit `long` for the new length, which silently truncates files (and\nthe requested size) to 2 GiB. That is enough to make t7508 test 126\n\"git add fails gracefully with 4 GiB and 8 GiB files\" fail under\nMSVC: `test-tool truncate` creates a sparse 4 GiB or 8 GiB file via\nthe shimmed `ftruncate()`, and the test never gets off the ground.\n\n`_chsize_s()` is the modern replacement, accepts a 64-bit `__int64`\nlength, and is the only sensible target on Windows. The catch is that\nit does not follow the POSIX `-1` + `errno` convention: it returns\n`0` on success and an errno value (a small positive integer) on\nfailure. A plain `#define ftruncate _chsize_s` would therefore\nsilently break callers that test the return value as `< 0` or against\n`-1`, of which there are several: `http.c`, `parallel-checkout.c`,\nand `t/helper/test-truncate.c` among them.\n\nIntroduce a `static inline` wrapper that calls `_chsize_s()`, copies\nits errno return into `errno`, and translates the result to the\nfamiliar `-1` / `0` convention, then point `ftruncate` at the\nwrapper. Place the wrapper after `#include \"mingw-posix.h\"` so the\n`off_t` parameter resolves to the already-widened `off64_t` rather\nthan the 32-bit `_off_t` from `compat/vcbuild/include/unistd.h`.\n\nMinGW is unaffected: its `ftruncate()` already takes `off_t` and\nroutes through `ftruncate64()` when `_FILE_OFFSET_BITS=64`, which is\nthe default in our build.\n\nAssisted-by: Opus 4.7\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n compat/msvc-posix.h | 24 +++++++++++++++++++++++-\n 1 file changed, 23 insertions(+), 1 deletion(-)\n\ndiff --git a/compat/msvc-posix.h b/compat/msvc-posix.h\nindex c500b8b4aa..7ce39b8d3f 100644\n--- a/compat/msvc-posix.h\n+++ b/compat/msvc-posix.h\n@@ -16,7 +16,6 @@\n #define __attribute__(x)\n #define strcasecmp   _stricmp\n #define strncasecmp  _strnicmp\n-#define ftruncate    _chsize\n #define strtoull     _strtoui64\n #define strtoll      _strtoi64\n \n@@ -30,4 +29,27 @@ typedef int sigset_t;\n \n #include \"mingw-posix.h\"\n \n+/*\n+ * MSVC's `_chsize()` takes a 32-bit `long` and silently truncates files\n+ * to 2 GiB. `_chsize_s()` accepts a 64-bit length but returns 0 on\n+ * success or an errno value on failure, rather than the -1/errno\n+ * convention POSIX `ftruncate()` callers expect. Wrap it so callers\n+ * that test the return value as `< 0` or against `-1` keep working.\n+ *\n+ * Note: this declaration must follow `#include \"mingw-posix.h\"` so\n+ * `off_t` resolves to `off64_t` and the parameter type matches the\n+ * underlying `_chsize_s()` width.\n+ */\n+static inline int msvc_ftruncate(int fd, off_t length)\n+{\n+\tint err = _chsize_s(fd, length);\n+\n+\tif (err) {\n+\t\terrno = err;\n+\t\treturn -1;\n+\t}\n+\treturn 0;\n+}\n+#define ftruncate msvc_ftruncate\n+\n #endif /* COMPAT_MSVC_POSIX_H */\n-- \ngitgitgadget\n\n"},{"id":"545543","messageId":"66a642c39e7755755fe388af7612ac8c9bf41a5a.1781524349.git.gitgitgadget@gmail.com","threadId":"65750","inReplyTo":"pull.2137.v2.git.1781524349.gitgitgadget@gmail.com","subject":"[PATCH v2 2/7] patch-delta: use size_t for sizes","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2026-06-15T11:52:24Z","receivedAt":"2026-06-15T11:52:35Z","isPatch":true,"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\n`patch_delta()` takes the source and delta sizes by value and writes\nback the reconstructed target size through an `unsigned long *`.  That\ndatatype cannot represent a value that exceeds 4 GiB on systems where\n`unsigned long` is 32-bit (notably 64-bit Windows builds), though, even\nthough the delta encoding itself, the on-disk layout, and the in-memory\nbuffers happily carry such sizes. A `size_t` companion to\n`get_delta_hdr_size()`, `get_delta_hdr_size_sz()`, was introduced in\n17fa077596 (delta, packfile: use size_t for delta header sizes,\n2026-05-08) precisely so that `patch_delta()` could be widened without\nchanging the on-the-wire decoding helper's signature.\n\nWiden `patch_delta()`'s three size parameters to `size_t` and switch\nits internal use of `get_delta_hdr_size()` to the `_sz` variant.\nThen propagate the wider type through the callers.\n\nAssisted-by: Opus 4.7\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n apply.c                  |  2 +-\n builtin/index-pack.c     |  4 ++--\n builtin/unpack-objects.c |  2 +-\n delta.h                  |  6 +++---\n packfile.c               |  4 +---\n patch-delta.c            | 12 ++++++------\n t/helper/test-delta.c    | 10 ++++++----\n 7 files changed, 20 insertions(+), 20 deletions(-)\n\ndiff --git a/apply.c b/apply.c\nindex 249248d4f2..3cf544e9a9 100644\n--- a/apply.c\n+++ b/apply.c\n@@ -3232,7 +3232,7 @@ static int apply_binary_fragment(struct apply_state *state,\n \t\t\t\t struct patch *patch)\n {\n \tstruct fragment *fragment = patch->fragments;\n-\tunsigned long len;\n+\tsize_t len;\n \tvoid *dst;\n \n \tif (!fragment)\ndiff --git a/builtin/index-pack.c b/builtin/index-pack.c\nindex cf0bd8280d..3c4474e681 100644\n--- a/builtin/index-pack.c\n+++ b/builtin/index-pack.c\n@@ -71,7 +71,7 @@ struct base_data {\n \t/* Not initialized by make_base(). */\n \tstruct list_head list;\n \tvoid *data;\n-\tunsigned long size;\n+\tsize_t size;\n };\n \n /*\n@@ -1048,7 +1048,7 @@ static struct base_data *resolve_delta(struct object_entry *delta_obj,\n {\n \tvoid *delta_data, *result_data;\n \tstruct base_data *result;\n-\tunsigned long result_size;\n+\tsize_t result_size;\n \n \tif (show_stat) {\n \t\tint i = delta_obj - objects;\ndiff --git a/builtin/unpack-objects.c b/builtin/unpack-objects.c\nindex 59e9b8711e..e7a50c493c 100644\n--- a/builtin/unpack-objects.c\n+++ b/builtin/unpack-objects.c\n@@ -314,7 +314,7 @@ static void resolve_delta(unsigned nr, enum object_type type,\n \t\t\t  void *delta, unsigned long delta_size)\n {\n \tvoid *result;\n-\tunsigned long result_size;\n+\tsize_t result_size;\n \n \tresult = patch_delta(base, base_size,\n \t\t\t     delta, delta_size,\ndiff --git a/delta.h b/delta.h\nindex fad68cfc45..bb149dc82b 100644\n--- a/delta.h\n+++ b/delta.h\n@@ -75,9 +75,9 @@ diff_delta(const void *src_buf, unsigned long src_bufsize,\n  * *trg_bufsize is updated with its size.  On failure a NULL pointer is\n  * returned.  The returned buffer must be freed by the caller.\n  */\n-void *patch_delta(const void *src_buf, unsigned long src_size,\n-\t\t  const void *delta_buf, unsigned long delta_size,\n-\t\t  unsigned long *dst_size);\n+void *patch_delta(const void *src_buf, size_t src_size,\n+\t\t  const void *delta_buf, size_t delta_size,\n+\t\t  size_t *dst_size);\n \n /* the smallest possible delta size is 4 bytes */\n #define DELTA_SIZE_MIN\t4\ndiff --git a/packfile.c b/packfile.c\nindex 89366abfe3..e202f48837 100644\n--- a/packfile.c\n+++ b/packfile.c\n@@ -1964,10 +1964,8 @@ void *unpack_entry(struct repository *r, struct packed_git *p, off_t obj_offset,\n \t\t\t      (uintmax_t)curpos, p->pack_name);\n \t\t\tdata = NULL;\n \t\t} else {\n-\t\t\tunsigned long sz;\n \t\t\tdata = patch_delta(base, base_size, delta_data,\n-\t\t\t\t\t   delta_size, &sz);\n-\t\t\tsize = sz;\n+\t\t\t\t\t   delta_size, &size);\n \n \t\t\t/*\n \t\t\t * We could not apply the delta; warn the user, but\ndiff --git a/patch-delta.c b/patch-delta.c\nindex b5c8594db6..44cda97994 100644\n--- a/patch-delta.c\n+++ b/patch-delta.c\n@@ -12,13 +12,13 @@\n #include \"git-compat-util.h\"\n #include \"delta.h\"\n \n-void *patch_delta(const void *src_buf, unsigned long src_size,\n-\t\t  const void *delta_buf, unsigned long delta_size,\n-\t\t  unsigned long *dst_size)\n+void *patch_delta(const void *src_buf, size_t src_size,\n+\t\t  const void *delta_buf, size_t delta_size,\n+\t\t  size_t *dst_size)\n {\n \tconst unsigned char *data, *top;\n \tunsigned char *dst_buf, *out, cmd;\n-\tunsigned long size;\n+\tsize_t size;\n \n \tif (delta_size < DELTA_SIZE_MIN)\n \t\treturn NULL;\n@@ -27,12 +27,12 @@ void *patch_delta(const void *src_buf, unsigned long src_size,\n \ttop = (const unsigned char *) delta_buf + delta_size;\n \n \t/* make sure the orig file size matches what we expect */\n-\tsize = get_delta_hdr_size(&data, top);\n+\tsize = get_delta_hdr_size_sz(&data, top);\n \tif (size != src_size)\n \t\treturn NULL;\n \n \t/* now the result size */\n-\tsize = get_delta_hdr_size(&data, top);\n+\tsize = get_delta_hdr_size_sz(&data, top);\n \tdst_buf = xmallocz(size);\n \n \tout = dst_buf;\ndiff --git a/t/helper/test-delta.c b/t/helper/test-delta.c\nindex 52ea00c937..8223a60229 100644\n--- a/t/helper/test-delta.c\n+++ b/t/helper/test-delta.c\n@@ -21,7 +21,7 @@ int cmd__delta(int argc, const char **argv)\n \tint fd;\n \tstruct strbuf from = STRBUF_INIT, data = STRBUF_INIT;\n \tchar *out_buf;\n-\tunsigned long out_size;\n+\tsize_t out_size;\n \n \tif (argc != 5 || (strcmp(argv[1], \"-d\") && strcmp(argv[1], \"-p\")))\n \t\tusage(usage_str);\n@@ -31,11 +31,13 @@ int cmd__delta(int argc, const char **argv)\n \tif (strbuf_read_file(&data, argv[3], 0) < 0)\n \t\tdie_errno(\"unable to read '%s'\", argv[3]);\n \n-\tif (argv[1][1] == 'd')\n+\tif (argv[1][1] == 'd') {\n+\t\tunsigned long delta_size;\n \t\tout_buf = diff_delta(from.buf, from.len,\n \t\t\t\t     data.buf, data.len,\n-\t\t\t\t     &out_size, 0);\n-\telse\n+\t\t\t\t     &delta_size, 0);\n+\t\tout_size = delta_size;\n+\t} else\n \t\tout_buf = patch_delta(from.buf, from.len,\n \t\t\t\t      data.buf, data.len,\n \t\t\t\t      &out_size);\n-- \ngitgitgadget\n\n"},{"id":"545544","messageId":"271a5299e30cc85ea59c2d0b806a5677576de764.1781524349.git.gitgitgadget@gmail.com","threadId":"65750","inReplyTo":"pull.2137.v2.git.1781524349.gitgitgadget@gmail.com","subject":"[PATCH v2 3/7] pack-objects(check_pack_inflate()): use size_t instead of unsigned long","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2026-06-15T11:52:25Z","receivedAt":"2026-06-15T11:52:36Z","isPatch":true,"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\n`write_reuse_object()` learned to track its packed-object size as\n`size_t` in 606c192380 (odb, packfile: use size_t for streaming\nobject sizes, 2026-05-08), but the comparison sink it feeds,\n`check_pack_inflate()`, still takes the expected decompressed size\nas `unsigned long`. The call site bridges the mismatch with\n`cast_size_t_to_ulong()`, which on Windows turns a >4 GiB object\ninto an immediate die().\n\nThat function only uses `expect` once: as the right-hand side of a\n`stream.total_out == expect` equality test against zlib's counter.\nzlib's own `total_out` counter is `uLong` and is therefore still\n32-bit-bound on Windows. Widening `expect` to `size_t` cannot fix that,\nbut it is a strict improvement nonetheless: instead of dying outright,\nan oversized object now simply makes the equality fail and lets\n`write_reuse_object()` fall back to `write_no_reuse_object()`, which\ndecompresses and re-deflates the content (and which the larger\npack-objects widening series targets separately).\n\nDrop the `cast_size_t_to_ulong()` shim at the call site now that\nthe receiving parameter speaks the same type as `entry_size`.\n\nAssisted-by: Opus 4.7\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n builtin/pack-objects.c | 5 ++---\n 1 file changed, 2 insertions(+), 3 deletions(-)\n\ndiff --git a/builtin/pack-objects.c b/builtin/pack-objects.c\nindex 50675481e1..56d1bb498d 100644\n--- a/builtin/pack-objects.c\n+++ b/builtin/pack-objects.c\n@@ -453,7 +453,7 @@ static int check_pack_inflate(struct packed_git *p,\n \t\tstruct pack_window **w_curs,\n \t\toff_t offset,\n \t\toff_t len,\n-\t\tunsigned long expect)\n+\t\tsize_t expect)\n {\n \tgit_zstream stream;\n \tunsigned char fakebuf[4096], *in;\n@@ -671,8 +671,7 @@ static off_t write_reuse_object(struct hashfile *f, struct object_entry *entry,\n \tdatalen -= entry->in_pack_header_size;\n \n \tif (!pack_to_stdout && p->index_version == 1 &&\n-\t    check_pack_inflate(p, &w_curs, offset, datalen,\n-\t\t\t       cast_size_t_to_ulong(entry_size))) {\n+\t    check_pack_inflate(p, &w_curs, offset, datalen, entry_size)) {\n \t\terror(_(\"corrupt packed object for %s\"),\n \t\t      oid_to_hex(&entry->idx.oid));\n \t\tunuse_pack(&w_curs);\n-- \ngitgitgadget\n\n"},{"id":"545545","messageId":"5c329535df4bed84f16223ca2e1ffbf2854ba42a.1781524349.git.gitgitgadget@gmail.com","threadId":"65750","inReplyTo":"pull.2137.v2.git.1781524349.gitgitgadget@gmail.com","subject":"[PATCH v2 4/7] packfile: widen unpack_entry()'s size out-parameter to size_t","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2026-06-15T11:52:26Z","receivedAt":"2026-06-15T11:52:37Z","isPatch":true,"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nThe topic `js/objects-larger-than-4gb-on-windows` widened the streaming,\nindex-pack and unpack-objects paths to `size_t` but deliberately stopped\nat the in-memory `unpack_entry()` cascade, which still hands back the\nunpacked size through `unsigned long *`.  On Windows that boundary\ntruncates above 4 GiB because that data type is only 32 bits wide on\nthat platform.\n\nWiden the code path. Except `packed_object_info_with_index_pos()`: It\ncannot yet pass `oi->sizep` directly because the field is still\n`unsigned long *`; bridge it with a `size_t` temporary that narrows\nback, and let a later commit drop the bridge once the field is wide\ntoo. `gfi_unpack_entry()` keeps its narrow signature because fast-import\ntracks sizes through `unsigned long` everywhere it crosses subsystem\nboundaries, keeping its signature allows the scope of this commit to be\nsomewhat reasonable, still.\n\nAssisted-by: Opus 4.7\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n builtin/fast-import.c |  7 ++++++-\n pack-check.c          |  5 ++---\n packfile.c            | 28 +++++++++++++++++-----------\n packfile.h            |  3 ++-\n 4 files changed, 27 insertions(+), 16 deletions(-)\n\ndiff --git a/builtin/fast-import.c b/builtin/fast-import.c\nindex 82bc6dcc00..3dff898c43 100644\n--- a/builtin/fast-import.c\n+++ b/builtin/fast-import.c\n@@ -1239,6 +1239,8 @@ static void *gfi_unpack_entry(\n \tunsigned long *sizep)\n {\n \tenum object_type type;\n+\tsize_t size_st = 0;\n+\tvoid *data;\n \tstruct packed_git *p = all_packs[oe->pack_id];\n \tif (p == pack_data && p->pack_size < (pack_size + the_hash_algo->rawsz)) {\n \t\t/* The object is stored in the packfile we are writing to\n@@ -1260,7 +1262,10 @@ static void *gfi_unpack_entry(\n \t\t */\n \t\tp->pack_size = pack_size + the_hash_algo->rawsz;\n \t}\n-\treturn unpack_entry(the_repository, p, oe->idx.offset, &type, sizep);\n+\tdata = unpack_entry(the_repository, p, oe->idx.offset, &type, &size_st);\n+\tif (sizep)\n+\t\t*sizep = cast_size_t_to_ulong(size_st);\n+\treturn data;\n }\n \n static void load_tree(struct tree_entry *root)\ndiff --git a/pack-check.c b/pack-check.c\nindex 2792f34d25..5adfb3f272 100644\n--- a/pack-check.c\n+++ b/pack-check.c\n@@ -143,9 +143,8 @@ static int verify_packfile(struct repository *r,\n \t\t\tdata = NULL;\n \t\t\tdata_valid = 0;\n \t\t} else {\n-\t\t\tunsigned long sz;\n-\t\t\tdata = unpack_entry(r, p, entries[i].offset, &type, &sz);\n-\t\t\tsize = sz;\n+\t\t\tdata = unpack_entry(r, p, entries[i].offset, &type,\n+\t\t\t\t\t    &size);\n \t\t\tdata_valid = 1;\n \t\t}\n \ndiff --git a/packfile.c b/packfile.c\nindex e202f48837..dab0a9b16d 100644\n--- a/packfile.c\n+++ b/packfile.c\n@@ -1454,7 +1454,7 @@ struct delta_base_cache_entry {\n \tstruct delta_base_cache_key key;\n \tstruct list_head lru;\n \tvoid *data;\n-\tunsigned long size;\n+\tsize_t size;\n \tenum object_type type;\n };\n \n@@ -1525,7 +1525,7 @@ static void detach_delta_base_cache_entry(struct delta_base_cache_entry *ent)\n }\n \n static void *cache_or_unpack_entry(struct repository *r, struct packed_git *p,\n-\t\t\t\t   off_t base_offset, unsigned long *base_size,\n+\t\t\t\t   off_t base_offset, size_t *base_size,\n \t\t\t\t   enum object_type *type)\n {\n \tstruct delta_base_cache_entry *ent;\n@@ -1558,8 +1558,8 @@ void clear_delta_base_cache(void)\n }\n \n static void add_delta_base_cache(struct packed_git *p, off_t base_offset,\n-\t\t\t\t void *base, unsigned long base_size,\n-\t\t\t\t unsigned long delta_base_cache_limit,\n+\t\t\t\t void *base, size_t base_size,\n+\t\t\t\t size_t delta_base_cache_limit,\n \t\t\t\t enum object_type type)\n {\n \tstruct delta_base_cache_entry *ent;\n@@ -1614,10 +1614,13 @@ static int packed_object_info_with_index_pos(struct packed_git *p, off_t obj_off\n \t * a \"real\" type later if the caller is interested.\n \t */\n \tif (oi->contentp) {\n-\t\t*oi->contentp = cache_or_unpack_entry(p->repo, p, obj_offset, oi->sizep,\n-\t\t\t\t\t\t      &type);\n+\t\tsize_t size_st = 0;\n+\t\t*oi->contentp = cache_or_unpack_entry(p->repo, p, obj_offset,\n+\t\t\t\t\t\t      &size_st, &type);\n \t\tif (!*oi->contentp)\n \t\t\ttype = OBJ_BAD;\n+\t\telse if (oi->sizep)\n+\t\t\t*oi->sizep = cast_size_t_to_ulong(size_st);\n \t} else if (oi->sizep || oi->typep || oi->delta_base_oid) {\n \t\ttype = unpack_object_header(p, &w_curs, &curpos, &size);\n \t}\n@@ -1735,7 +1738,7 @@ int packed_object_info(struct packed_git *p, off_t obj_offset,\n static void *unpack_compressed_entry(struct packed_git *p,\n \t\t\t\t    struct pack_window **w_curs,\n \t\t\t\t    off_t curpos,\n-\t\t\t\t    unsigned long size)\n+\t\t\t\t    size_t size)\n {\n \tint st;\n \tgit_zstream stream;\n@@ -1790,11 +1793,11 @@ int do_check_packed_object_crc;\n struct unpack_entry_stack_ent {\n \toff_t obj_offset;\n \toff_t curpos;\n-\tunsigned long size;\n+\tsize_t size;\n };\n \n void *unpack_entry(struct repository *r, struct packed_git *p, off_t obj_offset,\n-\t\t   enum object_type *final_type, unsigned long *final_size)\n+\t\t   enum object_type *final_type, size_t *final_size)\n {\n \tstruct pack_window *w_curs = NULL;\n \toff_t curpos = obj_offset;\n@@ -1911,7 +1914,7 @@ void *unpack_entry(struct repository *r, struct packed_git *p, off_t obj_offset,\n \t\tvoid *delta_data;\n \t\tvoid *base = data;\n \t\tvoid *external_base = NULL;\n-\t\tunsigned long delta_size, base_size = size;\n+\t\tsize_t delta_size, base_size = size;\n \t\tint i;\n \t\toff_t base_obj_offset = obj_offset;\n \n@@ -1928,6 +1931,7 @@ void *unpack_entry(struct repository *r, struct packed_git *p, off_t obj_offset,\n \t\t\tstruct object_id base_oid;\n \t\t\tif (!(offset_to_pack_pos(p, obj_offset, &pos))) {\n \t\t\t\tstruct object_info oi = OBJECT_INFO_INIT;\n+\t\t\t\tunsigned long bsz_ul = 0;\n \n \t\t\t\tnth_packed_object_id(&base_oid, p,\n \t\t\t\t\t\t     pack_pos_to_index(p, pos));\n@@ -1938,11 +1942,13 @@ void *unpack_entry(struct repository *r, struct packed_git *p, off_t obj_offset,\n \t\t\t\tmark_bad_packed_object(p, &base_oid);\n \n \t\t\t\toi.typep = &type;\n-\t\t\t\toi.sizep = &base_size;\n+\t\t\t\toi.sizep = &bsz_ul;\n \t\t\t\toi.contentp = &base;\n \t\t\t\tif (odb_read_object_info_extended(r->objects, &base_oid,\n \t\t\t\t\t\t\t\t  &oi, 0) < 0)\n \t\t\t\t\tbase = NULL;\n+\t\t\t\telse\n+\t\t\t\t\tbase_size = bsz_ul;\n \n \t\t\t\texternal_base = base;\n \t\t\t}\ndiff --git a/packfile.h b/packfile.h\nindex 49d6bdecf6..0b5ae3f9fc 100644\n--- a/packfile.h\n+++ b/packfile.h\n@@ -455,7 +455,8 @@ off_t nth_packed_object_offset(const struct packed_git *, uint32_t n);\n off_t find_pack_entry_one(const struct object_id *oid, struct packed_git *);\n \n int is_pack_valid(struct packed_git *);\n-void *unpack_entry(struct repository *r, struct packed_git *, off_t, enum object_type *, unsigned long *);\n+void *unpack_entry(struct repository *r, struct packed_git *, off_t,\n+\t\t   enum object_type *, size_t *);\n unsigned long unpack_object_header_buffer(const unsigned char *buf, unsigned long len, enum object_type *type, size_t *sizep);\n unsigned long get_size_from_delta(struct packed_git *, struct pack_window **, off_t);\n int unpack_object_header(struct packed_git *, struct pack_window **, off_t *, size_t *);\n-- \ngitgitgadget\n\n"},{"id":"545546","messageId":"01b9209b26335c0c4744e7f76684f823eebb69a5.1781524349.git.gitgitgadget@gmail.com","threadId":"65750","inReplyTo":"pull.2137.v2.git.1781524349.gitgitgadget@gmail.com","subject":"[PATCH v2 5/7] pack-objects: use size_t for in-core object sizes","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2026-06-15T11:52:27Z","receivedAt":"2026-06-15T11:52:39Z","isPatch":true,"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\n`pack-objects` stores per-entry object sizes in either the 31-bit\n`size_` member of the `struct object_entry` or, when the value does not\nfit, the `pack->delta_size[]` spill array.  The accessors (`oe_size`,\n`oe_delta_size`, `oe_get_size_slow`, `oe_size_*_than`) and the setters\n(`oe_set_size`, `oe_set_delta_size`) used `unsigned long` for the spill\ntype, which on Windows means the spill silently caps at 4 GiB per entry.\nThat is what made `upload-pack` die with \"object too large to read on\nthis platform\" when serving the >4 GiB blob in `t5608` tests 5 and 6\nwhen run with `GIT_TEST_CLONE_2GB`.\n\nWiden them all to `size_t` (including `pack->delta_size`) and drop the\nthree `cast_size_t_to_ulong()` calls in `check_object()` that guarded\n`in_pack_size`.  The two `SET_SIZE(entry, canonical_size)` calls in the\nsame function stay cast-free as before, since `canonical_size` is still\n`unsigned long` until a later commit widens `object_info::sizep`.\n\nAssisted-by: Opus 4.7\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n builtin/pack-objects.c | 35 ++++++++++++++++++-----------------\n pack-objects.h         |  2 +-\n 2 files changed, 19 insertions(+), 18 deletions(-)\n\ndiff --git a/builtin/pack-objects.c b/builtin/pack-objects.c\nindex 56d1bb498d..961d547ef2 100644\n--- a/builtin/pack-objects.c\n+++ b/builtin/pack-objects.c\n@@ -66,8 +66,8 @@ static inline struct object_entry *oe_delta(\n \t\treturn &pack->objects[e->delta_idx - 1];\n }\n \n-static inline unsigned long oe_delta_size(struct packing_data *pack,\n-\t\t\t\t\t  const struct object_entry *e)\n+static inline size_t oe_delta_size(struct packing_data *pack,\n+\t\t\t\t   const struct object_entry *e)\n {\n \tif (e->delta_size_valid)\n \t\treturn e->delta_size_;\n@@ -83,11 +83,11 @@ static inline unsigned long oe_delta_size(struct packing_data *pack,\n \treturn pack->delta_size[e - pack->objects];\n }\n \n-unsigned long oe_get_size_slow(struct packing_data *pack,\n-\t\t\t       const struct object_entry *e);\n+size_t oe_get_size_slow(struct packing_data *pack,\n+\t\t\tconst struct object_entry *e);\n \n-static inline unsigned long oe_size(struct packing_data *pack,\n-\t\t\t\t    const struct object_entry *e)\n+static inline size_t oe_size(struct packing_data *pack,\n+\t\t\t     const struct object_entry *e)\n {\n \tif (e->size_valid)\n \t\treturn e->size_;\n@@ -145,7 +145,7 @@ static inline void oe_set_delta_sibling(struct packing_data *pack,\n \n static inline void oe_set_size(struct packing_data *pack,\n \t\t\t       struct object_entry *e,\n-\t\t\t       unsigned long size)\n+\t\t\t       size_t size)\n {\n \tif (size < pack->oe_size_limit) {\n \t\te->size_ = size;\n@@ -159,7 +159,7 @@ static inline void oe_set_size(struct packing_data *pack,\n \n static inline void oe_set_delta_size(struct packing_data *pack,\n \t\t\t\t     struct object_entry *e,\n-\t\t\t\t     unsigned long size)\n+\t\t\t\t     size_t size)\n {\n \tif (size < pack->oe_delta_size_limit) {\n \t\te->delta_size_ = size;\n@@ -496,7 +496,7 @@ static void copy_pack_data(struct hashfile *f,\n \n static inline int oe_size_greater_than(struct packing_data *pack,\n \t\t\t\t       const struct object_entry *lhs,\n-\t\t\t\t       unsigned long rhs)\n+\t\t\t\t       size_t rhs)\n {\n \tif (lhs->size_valid)\n \t\treturn lhs->size_ > rhs;\n@@ -2279,7 +2279,7 @@ static void check_object(struct object_entry *entry, uint32_t object_index)\n \t\tdefault:\n \t\t\t/* Not a delta hence we've already got all we need. */\n \t\t\toe_set_type(entry, entry->in_pack_type);\n-\t\t\tSET_SIZE(entry, cast_size_t_to_ulong(in_pack_size));\n+\t\t\tSET_SIZE(entry, in_pack_size);\n \t\t\tentry->in_pack_header_size = used;\n \t\t\tif (oe_type(entry) < OBJ_COMMIT || oe_type(entry) > OBJ_BLOB)\n \t\t\t\tgoto give_up;\n@@ -2333,8 +2333,8 @@ static void check_object(struct object_entry *entry, uint32_t object_index)\n \t\tif (have_base &&\n \t\t    can_reuse_delta(&base_ref, entry, &base_entry)) {\n \t\t\toe_set_type(entry, entry->in_pack_type);\n-\t\t\tSET_SIZE(entry, cast_size_t_to_ulong(in_pack_size)); /* delta size */\n-\t\t\tSET_DELTA_SIZE(entry, cast_size_t_to_ulong(in_pack_size));\n+\t\t\tSET_SIZE(entry, in_pack_size); /* delta size */\n+\t\t\tSET_DELTA_SIZE(entry, in_pack_size);\n \n \t\t\tif (base_entry) {\n \t\t\t\tSET_DELTA(entry, base_entry);\n@@ -2357,7 +2357,8 @@ static void check_object(struct object_entry *entry, uint32_t object_index)\n \t\t\t * object size from the delta header.\n \t\t\t */\n \t\t\tdelta_pos = entry->in_pack_offset + entry->in_pack_header_size;\n-\t\t\tcanonical_size = get_size_from_delta(p, &w_curs, delta_pos);\n+\t\t\tcanonical_size = get_size_from_delta(p, &w_curs,\n+\t\t\t\t\t\t\t     delta_pos);\n \t\t\tif (canonical_size == 0)\n \t\t\t\tgoto give_up;\n \t\t\tSET_SIZE(entry, canonical_size);\n@@ -2713,7 +2714,7 @@ static pthread_mutex_t progress_mutex;\n \n static inline int oe_size_less_than(struct packing_data *pack,\n \t\t\t\t    const struct object_entry *lhs,\n-\t\t\t\t    unsigned long rhs)\n+\t\t\t\t    size_t rhs)\n {\n \tif (lhs->size_valid)\n \t\treturn lhs->size_ < rhs;\n@@ -2736,8 +2737,8 @@ static inline void oe_set_tree_depth(struct packing_data *pack,\n  * reconstruction (so non-deltas are true object sizes, but deltas\n  * return the size of the delta data).\n  */\n-unsigned long oe_get_size_slow(struct packing_data *pack,\n-\t\t\t       const struct object_entry *e)\n+size_t oe_get_size_slow(struct packing_data *pack,\n+\t\t\tconst struct object_entry *e)\n {\n \tstruct packed_git *p;\n \tstruct pack_window *w_curs;\n@@ -2771,7 +2772,7 @@ unsigned long oe_get_size_slow(struct packing_data *pack,\n \n \tunuse_pack(&w_curs);\n \tpacking_data_unlock(&to_pack);\n-\treturn cast_size_t_to_ulong(size);\n+\treturn size;\n }\n \n static int try_delta(struct unpacked *trg, struct unpacked *src,\ndiff --git a/pack-objects.h b/pack-objects.h\nindex 83299d4732..e97e84ddcb 100644\n--- a/pack-objects.h\n+++ b/pack-objects.h\n@@ -141,7 +141,7 @@ struct packing_data {\n \tuint32_t index_size;\n \n \tunsigned int *in_pack_pos;\n-\tunsigned long *delta_size;\n+\tsize_t *delta_size;\n \n \t/*\n \t * Only one of these can be non-NULL and they have different\n-- \ngitgitgadget\n\n"},{"id":"545547","messageId":"12c142f8abb0df11f716a9cf6d0e4f41966f8548.1781524349.git.gitgitgadget@gmail.com","threadId":"65750","inReplyTo":"pull.2137.v2.git.1781524349.gitgitgadget@gmail.com","subject":"[PATCH v2 6/7] packfile,delta: drop the `cast_size_t_to_ulong()` wrappers","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2026-06-15T11:52:28Z","receivedAt":"2026-06-15T11:52:41Z","isPatch":true,"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nWhen I started the transition from `unsigned long` to `size_t`, in the\ninterest of keeping the patches reviewable, I introduced these calls to\nprevent data type narrowing from silently failing to handle large object\nsizes. I also introduced `*_sz()` variants that would allow most of the\ncallers to keep using that `unsigned long` that the 90s kindly asked to\nbe returned.\n\nAfter the preceding commits, the only places that called the narrow\nwrappers either no longer exist or already use the `_sz` form\ninternally, so the wrappers just narrow values back through\n`cast_size_t_to_ulong()` for no reason.\n\nDrop them and rename the `_sz` variants back to the natural names.\n\nAssisted-by: Opus 4.7\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n delta.h       | 14 ++------------\n packfile.c    | 28 ++++++++--------------------\n packfile.h    |  2 +-\n patch-delta.c |  4 ++--\n 4 files changed, 13 insertions(+), 35 deletions(-)\n\ndiff --git a/delta.h b/delta.h\nindex bb149dc82b..eb5c6d2fdb 100644\n--- a/delta.h\n+++ b/delta.h\n@@ -86,11 +86,8 @@ void *patch_delta(const void *src_buf, size_t src_size,\n  * This must be called twice on the delta data buffer, first to get the\n  * expected source buffer size, and again to get the target buffer size.\n  */\n-/*\n- * Size_t variant that doesn't truncate - use for >4GB objects on Windows.\n- */\n-static inline size_t get_delta_hdr_size_sz(const unsigned char **datap,\n-\t\t\t\t\t   const unsigned char *top)\n+static inline size_t get_delta_hdr_size(const unsigned char **datap,\n+\t\t\t\t\tconst unsigned char *top)\n {\n \tconst unsigned char *data = *datap;\n \tsize_t cmd, size = 0;\n@@ -104,11 +101,4 @@ static inline size_t get_delta_hdr_size_sz(const unsigned char **datap,\n \treturn size;\n }\n \n-static inline unsigned long get_delta_hdr_size(const unsigned char **datap,\n-\t\t\t\t\t       const unsigned char *top)\n-{\n-\tsize_t size = get_delta_hdr_size_sz(datap, top);\n-\treturn cast_size_t_to_ulong(size);\n-}\n-\n #endif\ndiff --git a/packfile.c b/packfile.c\nindex dab0a9b16d..c174982d10 100644\n--- a/packfile.c\n+++ b/packfile.c\n@@ -1164,11 +1164,12 @@ unsigned long unpack_object_header_buffer(const unsigned char *buf,\n }\n \n /*\n- * Size_t variant for >4GB delta results on Windows.\n+ * Read a delta object's header at curpos in p (already inflated as needed)\n+ * and return the size of the result object (the post-application target).\n  */\n-static size_t get_size_from_delta_sz(struct packed_git *p,\n-\t\t\t\t     struct pack_window **w_curs,\n-\t\t\t\t     off_t curpos)\n+size_t get_size_from_delta(struct packed_git *p,\n+\t\t\t   struct pack_window **w_curs,\n+\t\t\t   off_t curpos)\n {\n \tconst unsigned char *data;\n \tunsigned char delta_head[20], *in;\n@@ -1215,18 +1216,10 @@ static size_t get_size_from_delta_sz(struct packed_git *p,\n \tdata = delta_head;\n \n \t/* ignore base size */\n-\tget_delta_hdr_size_sz(&data, delta_head+sizeof(delta_head));\n+\tget_delta_hdr_size(&data, delta_head+sizeof(delta_head));\n \n \t/* Read the result size */\n-\treturn get_delta_hdr_size_sz(&data, delta_head+sizeof(delta_head));\n-}\n-\n-unsigned long get_size_from_delta(struct packed_git *p,\n-\t\t\t\t  struct pack_window **w_curs,\n-\t\t\t\t  off_t curpos)\n-{\n-\tsize_t size = get_size_from_delta_sz(p, w_curs, curpos);\n-\treturn cast_size_t_to_ulong(size);\n+\treturn get_delta_hdr_size(&data, delta_head+sizeof(delta_head));\n }\n \n int unpack_object_header(struct packed_git *p,\n@@ -1634,12 +1627,7 @@ static int packed_object_info_with_index_pos(struct packed_git *p, off_t obj_off\n \t\t\t\tret = -1;\n \t\t\t\tgoto out;\n \t\t\t}\n-\t\t\t/*\n-\t\t\t * Use size_t variant to avoid die() on >4GB deltas.\n-\t\t\t * oi->sizep is unsigned long, so truncation may occur,\n-\t\t\t * but streaming code uses its own size_t tracking.\n-\t\t\t */\n-\t\t\tsize = get_size_from_delta_sz(p, &w_curs, tmp_pos);\n+\t\t\tsize = get_size_from_delta(p, &w_curs, tmp_pos);\n \t\t\tif (size == 0) {\n \t\t\t\tret = -1;\n \t\t\t\tgoto out;\ndiff --git a/packfile.h b/packfile.h\nindex 0b5ae3f9fc..bd4494906d 100644\n--- a/packfile.h\n+++ b/packfile.h\n@@ -458,7 +458,7 @@ int is_pack_valid(struct packed_git *);\n void *unpack_entry(struct repository *r, struct packed_git *, off_t,\n \t\t   enum object_type *, size_t *);\n unsigned long unpack_object_header_buffer(const unsigned char *buf, unsigned long len, enum object_type *type, size_t *sizep);\n-unsigned long get_size_from_delta(struct packed_git *, struct pack_window **, off_t);\n+size_t get_size_from_delta(struct packed_git *, struct pack_window **, off_t);\n int unpack_object_header(struct packed_git *, struct pack_window **, off_t *, size_t *);\n off_t get_delta_base(struct packed_git *p, struct pack_window **w_curs,\n \t\t     off_t *curpos, enum object_type type,\ndiff --git a/patch-delta.c b/patch-delta.c\nindex 44cda97994..42199fa956 100644\n--- a/patch-delta.c\n+++ b/patch-delta.c\n@@ -27,12 +27,12 @@ void *patch_delta(const void *src_buf, size_t src_size,\n \ttop = (const unsigned char *) delta_buf + delta_size;\n \n \t/* make sure the orig file size matches what we expect */\n-\tsize = get_delta_hdr_size_sz(&data, top);\n+\tsize = get_delta_hdr_size(&data, top);\n \tif (size != src_size)\n \t\treturn NULL;\n \n \t/* now the result size */\n-\tsize = get_delta_hdr_size_sz(&data, top);\n+\tsize = get_delta_hdr_size(&data, top);\n \tdst_buf = xmallocz(size);\n \n \tout = dst_buf;\n-- \ngitgitgadget\n\n"},{"id":"545548","messageId":"37d030d8675e94caee2eecb8398691d385d444bd.1781524349.git.gitgitgadget@gmail.com","threadId":"65750","inReplyTo":"pull.2137.v2.git.1781524349.gitgitgadget@gmail.com","subject":"[PATCH v2 7/7] odb: use size_t for object_info.sizep and the size APIs","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2026-06-15T11:52:29Z","receivedAt":"2026-06-15T11:52:44Z","isPatch":true,"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nWhen `js/objects-larger-than-4gb-on-windows` widened the streaming,\nindex-pack and unpack-objects code paths, in the interest of keeping the\npatches somewhat reasonably-sized, it left the public ODB API still\ntyped in `unsigned long`. In particular `struct object_info::sizep` and\nthe four wrappers built on top of it (`odb_read_object`,\n`odb_read_object_peeled`, `odb_read_object_info`, `odb_pretend_object`)\nstill return the unpacked size through `unsigned long *`, so on Windows\n`cat-file -s` and the `git add` / `git status` paths for a >4 GiB blob\nsilently cap at 4 GiB.\n\nWiden the field and the four wrappers. The previous commits already\nwidened the `unpack_entry()` cascade and pack-objects' in-core size\naccessors, so most of the cascade arrives here with no further work: the\ntemporary shims in `packed_object_info_with_index_pos()` and in\n`unpack_entry()`'s delta-base recovery path go away, the two\n`SET_SIZE(entry, cast_size_t_to_ulong(canonical_size))` calls in\n`check_object()` and the matching one in `drop_reused_delta()` collapse\nto plain `SET_SIZE`, and `oe_get_size_slow()`'s tail\n`cast_size_t_to_ulong()` is gone too.\n\nWhat remains narrow are the boundaries this series does not\nintend to touch: the diff, blame, textconv and fast-import machinery.\n\nEven so, this patch is unfortunately quite large.\n\nAssisted-by: Opus 4.7\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n apply.c                       |  6 ++--\n archive.c                     |  4 +--\n attr.c                        |  2 +-\n bisect.c                      |  2 +-\n blame.c                       | 15 ++++++---\n builtin/cat-file.c            | 61 ++++++++++++++++-------------------\n builtin/difftool.c            |  2 +-\n builtin/fast-export.c         |  7 ++--\n builtin/fast-import.c         | 22 +++++++++----\n builtin/fsck.c                |  2 +-\n builtin/grep.c                | 12 +++----\n builtin/index-pack.c          |  6 ++--\n builtin/log.c                 |  2 +-\n builtin/ls-files.c            |  2 +-\n builtin/ls-tree.c             |  4 +--\n builtin/merge-tree.c          |  6 ++--\n builtin/mktag.c               |  2 +-\n builtin/notes.c               |  6 ++--\n builtin/pack-objects.c        | 33 +++++++++++++------\n builtin/repo.c                |  4 ++-\n builtin/tag.c                 |  4 +--\n builtin/unpack-file.c         |  2 +-\n builtin/unpack-objects.c      |  6 ++--\n bundle.c                      |  2 +-\n combine-diff.c                |  4 ++-\n commit.c                      | 10 +++---\n config.c                      |  2 +-\n diff.c                        |  5 ++-\n dir.c                         |  2 +-\n entry.c                       |  4 +--\n fmt-merge-msg.c               |  4 +--\n fsck.c                        |  2 +-\n grep.c                        |  4 ++-\n http-push.c                   |  2 +-\n list-objects-filter.c         |  2 +-\n mailmap.c                     |  2 +-\n match-trees.c                 |  4 +--\n merge-blobs.c                 |  6 ++--\n merge-blobs.h                 |  2 +-\n merge-ort.c                   |  2 +-\n notes-cache.c                 |  2 +-\n notes-merge.c                 |  2 +-\n notes.c                       |  8 +++--\n object-file.c                 |  6 ++--\n object.c                      |  2 +-\n odb.c                         | 12 +++----\n odb.h                         | 10 +++---\n odb/source-loose.c            | 12 ++-----\n odb/streaming.c               | 13 +-------\n pack-bitmap.c                 |  4 +--\n packfile.c                    | 12 ++-----\n path-walk.c                   |  2 +-\n protocol-caps.c               |  5 +--\n read-cache.c                  |  6 ++--\n ref-filter.c                  |  2 +-\n reflog.c                      |  2 +-\n rerere.c                      |  2 +-\n submodule-config.c            |  2 +-\n t/helper/test-pack-deltas.c   |  3 +-\n t/helper/test-partial-clone.c |  2 +-\n t/unit-tests/u-odb-inmemory.c |  2 +-\n tag.c                         |  4 +--\n tree-walk.c                   | 10 +++---\n tree.c                        |  2 +-\n xdiff-interface.c             |  2 +-\n 65 files changed, 209 insertions(+), 191 deletions(-)\n\ndiff --git a/apply.c b/apply.c\nindex 3cf544e9a9..5e54453f79 100644\n--- a/apply.c\n+++ b/apply.c\n@@ -3321,7 +3321,7 @@ static int apply_binary(struct apply_state *state,\n \tif (odb_has_object(the_repository->objects, &oid, 0)) {\n \t\t/* We already have the postimage */\n \t\tenum object_type type;\n-\t\tunsigned long size;\n+\t\tsize_t size;\n \t\tchar *result;\n \n \t\tresult = odb_read_object(the_repository->objects, &oid,\n@@ -3384,7 +3384,7 @@ static int read_blob_object(struct strbuf *buf, const struct object_id *oid, uns\n \t\tstrbuf_addf(buf, \"Subproject commit %s\\n\", oid_to_hex(oid));\n \t} else {\n \t\tenum object_type type;\n-\t\tunsigned long sz;\n+\t\tsize_t sz;\n \t\tchar *result;\n \n \t\tresult = odb_read_object(the_repository->objects, oid,\n@@ -3611,7 +3611,7 @@ static int load_preimage(struct apply_state *state,\n \n static int resolve_to(struct image *image, const struct object_id *result_id)\n {\n-\tunsigned long size;\n+\tsize_t size;\n \tenum object_type type;\n \tchar *data;\n \ndiff --git a/archive.c b/archive.c\nindex 51229107a5..59790be986 100644\n--- a/archive.c\n+++ b/archive.c\n@@ -87,7 +87,7 @@ static void *object_file_to_archive(const struct archiver_args *args,\n \t\t\t\t    const struct object_id *oid,\n \t\t\t\t    unsigned int mode,\n \t\t\t\t    enum object_type *type,\n-\t\t\t\t    unsigned long *sizep)\n+\t\t\t\t    size_t *sizep)\n {\n \tvoid *buffer;\n \tconst struct commit *commit = args->convert ? args->commit : NULL;\n@@ -158,7 +158,7 @@ static int write_archive_entry(const struct object_id *oid, const char *base,\n \twrite_archive_entry_fn_t write_entry = c->write_entry;\n \tint err;\n \tconst char *path_without_prefix;\n-\tunsigned long size;\n+\tsize_t size;\n \tvoid *buffer;\n \tenum object_type type;\n \ndiff --git a/attr.c b/attr.c\nindex 75369547b3..c61472a4e6 100644\n--- a/attr.c\n+++ b/attr.c\n@@ -768,7 +768,7 @@ static struct attr_stack *read_attr_from_blob(struct index_state *istate,\n \t\t\t\t\t      const char *path, unsigned flags)\n {\n \tstruct object_id oid;\n-\tunsigned long sz;\n+\tsize_t sz;\n \tenum object_type type;\n \tvoid *buf;\n \tunsigned short mode;\ndiff --git a/bisect.c b/bisect.c\nindex e29d1cbc64..94c7028d2a 100644\n--- a/bisect.c\n+++ b/bisect.c\n@@ -154,7 +154,7 @@ static void show_list(const char *debug, int counted, int nr,\n \t\tstruct commit *commit = p->item;\n \t\tunsigned commit_flags = commit->object.flags;\n \t\tenum object_type type;\n-\t\tunsigned long size;\n+\t\tsize_t size;\n \t\tchar *buf = odb_read_object(the_repository->objects,\n \t\t\t\t\t    &commit->object.oid, &type,\n \t\t\t\t\t    &size);\ndiff --git a/blame.c b/blame.c\nindex 977cbb7097..126e232416 100644\n--- a/blame.c\n+++ b/blame.c\n@@ -1041,10 +1041,13 @@ static void fill_origin_blob(struct diff_options *opt,\n \t\t    textconv_object(opt->repo, o->path, o->mode,\n \t\t\t\t    &o->blob_oid, 1, &file->ptr, &file_size))\n \t\t\t;\n-\t\telse\n+\t\telse {\n+\t\t\tsize_t file_size_st = 0;\n \t\t\tfile->ptr = odb_read_object(the_repository->objects,\n \t\t\t\t\t\t    &o->blob_oid, &type,\n-\t\t\t\t\t\t    &file_size);\n+\t\t\t\t\t\t    &file_size_st);\n+\t\t\tfile_size = cast_size_t_to_ulong(file_size_st);\n+\t\t}\n \t\tfile->size = file_size;\n \n \t\tif (!file->ptr)\n@@ -2869,10 +2872,14 @@ void setup_scoreboard(struct blame_scoreboard *sb,\n \t\t    textconv_object(sb->repo, sb->path, o->mode, &o->blob_oid, 1, (char **) &sb->final_buf,\n \t\t\t\t    &sb->final_buf_size))\n \t\t\t;\n-\t\telse\n+\t\telse {\n+\t\t\tsize_t final_buf_size_st = 0;\n \t\t\tsb->final_buf = odb_read_object(the_repository->objects,\n \t\t\t\t\t\t\t&o->blob_oid, &type,\n-\t\t\t\t\t\t\t&sb->final_buf_size);\n+\t\t\t\t\t\t\t&final_buf_size_st);\n+\t\t\tsb->final_buf_size =\n+\t\t\t\tcast_size_t_to_ulong(final_buf_size_st);\n+\t\t}\n \n \t\tif (!sb->final_buf)\n \t\t\tdie(_(\"cannot read blob %s for path %s\"),\ndiff --git a/builtin/cat-file.c b/builtin/cat-file.c\nindex 2b64f8f733..adb2ef5130 100644\n--- a/builtin/cat-file.c\n+++ b/builtin/cat-file.c\n@@ -84,7 +84,7 @@ static char *replace_idents_using_mailmap(char *object_buf, size_t *size)\n \n static int filter_object(const char *path, unsigned mode,\n \t\t\t const struct object_id *oid,\n-\t\t\t char **buf, unsigned long *size)\n+\t\t\t char **buf, size_t *size)\n {\n \tenum object_type type;\n \n@@ -120,7 +120,7 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name)\n \tstruct object_id oid;\n \tenum object_type type;\n \tchar *buf;\n-\tunsigned long size;\n+\tsize_t size;\n \tstruct object_context obj_context = {0};\n \tstruct object_info oi = OBJECT_INFO_INIT;\n \tunsigned flags = OBJECT_INFO_LOOKUP_REPLACE;\n@@ -163,11 +163,8 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name)\n \t\tif (odb_read_object_info_extended(the_repository->objects, &oid, &oi, flags) < 0)\n \t\t\tdie(\"git cat-file: could not get object info\");\n \n-\t\tif (use_mailmap && (type == OBJ_COMMIT || type == OBJ_TAG)) {\n-\t\t\tsize_t s = size;\n-\t\t\tbuf = replace_idents_using_mailmap(buf, &s);\n-\t\t\tsize = cast_size_t_to_ulong(s);\n-\t\t}\n+\t\tif (use_mailmap && (type == OBJ_COMMIT || type == OBJ_TAG))\n+\t\t\tbuf = replace_idents_using_mailmap(buf, &size);\n \n \t\tprintf(\"%\"PRIuMAX\"\\n\", (uintmax_t)size);\n \t\tret = 0;\n@@ -188,9 +185,15 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name)\n \t\tbreak;\n \n \tcase 'c':\n-\t\tif (textconv_object(the_repository, path, obj_context.mode,\n-\t\t\t\t    &oid, 1, &buf, &size))\n+\t{\n+\t\tunsigned long size_ul = 0;\n+\t\tint textconv_ret = textconv_object(the_repository, path,\n+\t\t\t\t\t\t   obj_context.mode, &oid, 1,\n+\t\t\t\t\t\t   &buf, &size_ul);\n+\t\tsize = size_ul;\n+\t\tif (textconv_ret)\n \t\t\tbreak;\n+\t}\n \t\t/* else fallthrough */\n \n \tcase 'p':\n@@ -216,11 +219,8 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name)\n \t\tif (!buf)\n \t\t\tdie(\"Cannot read object %s\", obj_name);\n \n-\t\tif (use_mailmap) {\n-\t\t\tsize_t s = size;\n-\t\t\tbuf = replace_idents_using_mailmap(buf, &s);\n-\t\t\tsize = cast_size_t_to_ulong(s);\n-\t\t}\n+\t\tif (use_mailmap)\n+\t\t\tbuf = replace_idents_using_mailmap(buf, &size);\n \n \t\t/* otherwise just spit out the data */\n \t\tbreak;\n@@ -263,11 +263,8 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name)\n \t\tbuf = odb_read_object_peeled(the_repository->objects, &oid,\n \t\t\t\t\t     exp_type_id, &size, NULL);\n \n-\t\tif (use_mailmap) {\n-\t\t\tsize_t s = size;\n-\t\t\tbuf = replace_idents_using_mailmap(buf, &s);\n-\t\t\tsize = cast_size_t_to_ulong(s);\n-\t\t}\n+\t\tif (use_mailmap)\n+\t\t\tbuf = replace_idents_using_mailmap(buf, &size);\n \t\tbreak;\n \t}\n \tdefault:\n@@ -288,7 +285,7 @@ cleanup:\n struct expand_data {\n \tstruct object_id oid;\n \tenum object_type type;\n-\tunsigned long size;\n+\tsize_t size;\n \tunsigned short mode;\n \toff_t disk_size;\n \tconst char *rest;\n@@ -404,7 +401,7 @@ static void print_object_or_die(struct batch_options *opt, struct expand_data *d\n \t\t\tfflush(stdout);\n \t\tif (opt->transform_mode) {\n \t\t\tchar *contents;\n-\t\t\tunsigned long size;\n+\t\t\tsize_t size;\n \n \t\t\tif (!data->rest)\n \t\t\t\tdie(\"missing path for '%s'\", oid_to_hex(oid));\n@@ -416,9 +413,12 @@ static void print_object_or_die(struct batch_options *opt, struct expand_data *d\n \t\t\t\t\t    oid_to_hex(oid), data->rest);\n \t\t\t} else if (opt->transform_mode == 'c') {\n \t\t\t\tenum object_type type;\n-\t\t\t\tif (!textconv_object(the_repository,\n-\t\t\t\t\t\t     data->rest, 0100644, oid,\n-\t\t\t\t\t\t     1, &contents, &size))\n+\t\t\t\tunsigned long size_ul = 0;\n+\t\t\t\tif (textconv_object(the_repository,\n+\t\t\t\t\t\t    data->rest, 0100644, oid,\n+\t\t\t\t\t\t    1, &contents, &size_ul))\n+\t\t\t\t\tsize = size_ul;\n+\t\t\t\telse\n \t\t\t\t\tcontents = odb_read_object(the_repository->objects,\n \t\t\t\t\t\t\t\t   oid, &type, &size);\n \t\t\t\tif (!contents)\n@@ -434,7 +434,7 @@ static void print_object_or_die(struct batch_options *opt, struct expand_data *d\n \t}\n \telse {\n \t\tenum object_type type;\n-\t\tunsigned long size;\n+\t\tsize_t size;\n \t\tvoid *contents;\n \n \t\tcontents = odb_read_object(the_repository->objects, oid,\n@@ -442,11 +442,8 @@ static void print_object_or_die(struct batch_options *opt, struct expand_data *d\n \t\tif (!contents)\n \t\t\tdie(\"object %s disappeared\", oid_to_hex(oid));\n \n-\t\tif (use_mailmap) {\n-\t\t\tsize_t s = size;\n-\t\t\tcontents = replace_idents_using_mailmap(contents, &s);\n-\t\t\tsize = cast_size_t_to_ulong(s);\n-\t\t}\n+\t\tif (use_mailmap)\n+\t\t\tcontents = replace_idents_using_mailmap(contents, &size);\n \n \t\tif (type != data->type)\n \t\t\tdie(\"object %s changed type!?\", oid_to_hex(oid));\n@@ -546,15 +543,13 @@ static void batch_object_write(const char *obj_name,\n \t\t}\n \n \t\tif (use_mailmap && (data->type == OBJ_COMMIT || data->type == OBJ_TAG)) {\n-\t\t\tsize_t s = data->size;\n \t\t\tchar *buf = NULL;\n \n \t\t\tbuf = odb_read_object(the_repository->objects, &data->oid,\n \t\t\t\t\t      &data->type, &data->size);\n \t\t\tif (!buf)\n \t\t\t\tdie(_(\"unable to read %s\"), oid_to_hex(&data->oid));\n-\t\t\tbuf = replace_idents_using_mailmap(buf, &s);\n-\t\t\tdata->size = cast_size_t_to_ulong(s);\n+\t\t\tbuf = replace_idents_using_mailmap(buf, &data->size);\n \n \t\t\tfree(buf);\n \t\t}\ndiff --git a/builtin/difftool.c b/builtin/difftool.c\nindex 2a21005f2e..26778f8515 100644\n--- a/builtin/difftool.c\n+++ b/builtin/difftool.c\n@@ -319,7 +319,7 @@ static char *get_symlink(struct repository *repo,\n \t\tdata = strbuf_detach(&link, NULL);\n \t} else {\n \t\tenum object_type type;\n-\t\tunsigned long size;\n+\t\tsize_t size;\n \t\tdata = odb_read_object(repo->objects, oid, &type, &size);\n \t\tif (!data)\n \t\t\tdie(_(\"could not read object %s for symlink %s\"),\ndiff --git a/builtin/fast-export.c b/builtin/fast-export.c\nindex 2eb43a28da..0be43104dc 100644\n--- a/builtin/fast-export.c\n+++ b/builtin/fast-export.c\n@@ -317,7 +317,10 @@ static void export_blob(const struct object_id *oid)\n \t\tobject = (struct object *)lookup_blob(the_repository, oid);\n \t\teaten = 0;\n \t} else {\n-\t\tbuf = odb_read_object(the_repository->objects, oid, &type, &size);\n+\t\tsize_t size_st = 0;\n+\t\tbuf = odb_read_object(the_repository->objects, oid, &type,\n+\t\t\t\t      &size_st);\n+\t\tsize = cast_size_t_to_ulong(size_st);\n \t\tif (!buf)\n \t\t\tdie(_(\"could not read blob %s\"), oid_to_hex(oid));\n \t\tif (check_object_signature(the_repository, oid, buf, size,\n@@ -880,7 +883,7 @@ static char *anonymize_tag(void)\n \n static void handle_tag(const char *name, struct tag *tag)\n {\n-\tunsigned long size;\n+\tsize_t size;\n \tenum object_type type;\n \tchar *buf;\n \tconst char *tagger, *tagger_end, *message;\ndiff --git a/builtin/fast-import.c b/builtin/fast-import.c\nindex 3dff898c43..d11a2cc2c1 100644\n--- a/builtin/fast-import.c\n+++ b/builtin/fast-import.c\n@@ -1291,7 +1291,10 @@ static void load_tree(struct tree_entry *root)\n \t\t\tdie(_(\"can't load tree %s\"), oid_to_hex(oid));\n \t} else {\n \t\tenum object_type type;\n-\t\tbuf = odb_read_object(the_repository->objects, oid, &type, &size);\n+\t\tsize_t size_st = 0;\n+\t\tbuf = odb_read_object(the_repository->objects, oid, &type,\n+\t\t\t\t      &size_st);\n+\t\tsize = cast_size_t_to_ulong(size_st);\n \t\tif (!buf || type != OBJ_TREE)\n \t\t\tdie(_(\"can't load tree %s\"), oid_to_hex(oid));\n \t}\n@@ -2560,7 +2563,7 @@ static void note_change_n(const char *p, struct branch *b, unsigned char *old_fa\n \t\t\tdie(_(\"mark :%\" PRIuMAX \" not a commit\"), commit_mark);\n \t\toidcpy(&commit_oid, &commit_oe->idx.oid);\n \t} else if (!repo_get_oid(the_repository, p, &commit_oid)) {\n-\t\tunsigned long size;\n+\t\tsize_t size;\n \t\tchar *buf = odb_read_object_peeled(the_repository->objects,\n \t\t\t\t\t\t   &commit_oid, OBJ_COMMIT, &size,\n \t\t\t\t\t\t   &commit_oid);\n@@ -2627,10 +2630,12 @@ static void parse_from_existing(struct branch *b)\n \t\toidclr(&b->branch_tree.versions[1].oid, the_repository->hash_algo);\n \t} else {\n \t\tunsigned long size;\n+\t\tsize_t size_st = 0;\n \t\tchar *buf;\n \n \t\tbuf = odb_read_object_peeled(the_repository->objects, &b->oid,\n-\t\t\t\t\t     OBJ_COMMIT, &size, &b->oid);\n+\t\t\t\t\t     OBJ_COMMIT, &size_st, &b->oid);\n+\t\tsize = cast_size_t_to_ulong(size_st);\n \t\tparse_from_commit(b, buf, size);\n \t\tfree(buf);\n \t}\n@@ -2722,7 +2727,7 @@ static struct hash_list *parse_merge(unsigned int *count)\n \t\t\t\tdie(_(\"mark :%\" PRIuMAX \" not a commit\"), idnum);\n \t\t\toidcpy(&n->oid, &oe->idx.oid);\n \t\t} else if (!repo_get_oid(the_repository, from, &n->oid)) {\n-\t\t\tunsigned long size;\n+\t\t\tsize_t size;\n \t\t\tchar *buf = odb_read_object_peeled(the_repository->objects,\n \t\t\t\t\t\t\t   &n->oid, OBJ_COMMIT,\n \t\t\t\t\t\t\t   &size, &n->oid);\n@@ -3330,7 +3335,10 @@ static void cat_blob(struct object_entry *oe, struct object_id *oid)\n \tchar *buf;\n \n \tif (!oe || oe->pack_id == MAX_PACK_ID) {\n-\t\tbuf = odb_read_object(the_repository->objects, oid, &type, &size);\n+\t\tsize_t size_st = 0;\n+\t\tbuf = odb_read_object(the_repository->objects, oid, &type,\n+\t\t\t\t      &size_st);\n+\t\tsize = cast_size_t_to_ulong(size_st);\n \t} else {\n \t\ttype = oe->type;\n \t\tbuf = gfi_unpack_entry(oe, &size);\n@@ -3438,8 +3446,10 @@ static struct object_entry *dereference(struct object_entry *oe,\n \t\tbuf = gfi_unpack_entry(oe, &size);\n \t} else {\n \t\tenum object_type unused;\n+\t\tsize_t size_st = 0;\n \t\tbuf = odb_read_object(the_repository->objects, oid,\n-\t\t\t\t      &unused, &size);\n+\t\t\t\t      &unused, &size_st);\n+\t\tsize = cast_size_t_to_ulong(size_st);\n \t}\n \tif (!buf)\n \t\tdie(_(\"can't load object %s\"), oid_to_hex(oid));\ndiff --git a/builtin/fsck.c b/builtin/fsck.c\nindex 248f8ff5a0..76b723f36d 100644\n--- a/builtin/fsck.c\n+++ b/builtin/fsck.c\n@@ -724,7 +724,7 @@ static int fsck_loose(const struct object_id *oid, const char *path,\n \tstruct for_each_loose_cb *data = cb_data;\n \tstruct object *obj;\n \tenum object_type type = OBJ_NONE;\n-\tunsigned long size;\n+\tsize_t size;\n \tvoid *contents = NULL;\n \tint eaten;\n \tstruct object_info oi = OBJECT_INFO_INIT;\ndiff --git a/builtin/grep.c b/builtin/grep.c\nindex 6a09571903..26b85479ca 100644\n--- a/builtin/grep.c\n+++ b/builtin/grep.c\n@@ -520,7 +520,7 @@ static int grep_submodule(struct grep_opt *opt,\n \t\tenum object_type object_type;\n \t\tstruct tree_desc tree;\n \t\tvoid *data;\n-\t\tunsigned long size;\n+\t\tsize_t size;\n \t\tstruct strbuf base = STRBUF_INIT;\n \n \t\tobj_read_lock();\n@@ -573,7 +573,7 @@ static int grep_cache(struct grep_opt *opt,\n \t\t\tenum object_type type;\n \t\t\tstruct tree_desc tree;\n \t\t\tvoid *data;\n-\t\t\tunsigned long size;\n+\t\t\tsize_t size;\n \n \t\t\tdata = odb_read_object(the_repository->objects, &ce->oid,\n \t\t\t\t\t       &type, &size);\n@@ -666,7 +666,7 @@ static int grep_tree(struct grep_opt *opt, const struct pathspec *pathspec,\n \t\t\tenum object_type type;\n \t\t\tstruct tree_desc sub;\n \t\t\tvoid *data;\n-\t\t\tunsigned long size;\n+\t\t\tsize_t size;\n \n \t\t\tdata = odb_read_object(the_repository->objects,\n \t\t\t\t\t       &entry.oid, &type, &size);\n@@ -730,7 +730,7 @@ static void collect_blob_oids_for_tree(struct repository *repo,\n \t\t\tenum object_type type;\n \t\t\tstruct tree_desc sub_tree;\n \t\t\tvoid *data;\n-\t\t\tunsigned long size;\n+\t\t\tsize_t size;\n \n \t\t\tdata = odb_read_object(repo->objects, &entry.oid,\n \t\t\t\t\t       &type, &size);\n@@ -764,7 +764,7 @@ static void collect_blob_oids_for_treeish(struct grep_opt *opt,\n {\n \tstruct tree_desc tree;\n \tvoid *data;\n-\tunsigned long size;\n+\tsize_t size;\n \tstruct strbuf base = STRBUF_INIT;\n \tint len;\n \n@@ -841,7 +841,7 @@ static int grep_object(struct grep_opt *opt, const struct pathspec *pathspec,\n \tif (obj->type == OBJ_COMMIT || obj->type == OBJ_TREE) {\n \t\tstruct tree_desc tree;\n \t\tvoid *data;\n-\t\tunsigned long size;\n+\t\tsize_t size;\n \t\tstruct strbuf base;\n \t\tint hit, len;\n \ndiff --git a/builtin/index-pack.c b/builtin/index-pack.c\nindex 3c4474e681..78da3a6566 100644\n--- a/builtin/index-pack.c\n+++ b/builtin/index-pack.c\n@@ -258,7 +258,7 @@ static unsigned check_object(struct object *obj)\n \t\treturn 0;\n \n \tif (!(obj->flags & FLAG_CHECKED)) {\n-\t\tunsigned long size;\n+\t\tsize_t size;\n \t\tint type = odb_read_object_info(the_repository->objects,\n \t\t\t\t\t\t&obj->oid, &size);\n \t\tif (type <= 0)\n@@ -905,7 +905,7 @@ static void sha1_object(const void *data, struct object_entry *obj_entry,\n \tif (collision_test_needed) {\n \t\tvoid *has_data;\n \t\tenum object_type has_type;\n-\t\tunsigned long has_size;\n+\t\tsize_t has_size;\n \t\tread_lock();\n \t\thas_type = odb_read_object_info(the_repository->objects, oid, &has_size);\n \t\tif (has_type < 0)\n@@ -1515,7 +1515,7 @@ static void fix_unresolved_deltas(struct hashfile *f)\n \t\tstruct ref_delta_entry *d = sorted_by_pos[i];\n \t\tenum object_type type;\n \t\tvoid *data;\n-\t\tunsigned long size;\n+\t\tsize_t size;\n \n \t\tif (objects[d->obj_no].real_type != OBJ_REF_DELTA)\n \t\t\tcontinue;\ndiff --git a/builtin/log.c b/builtin/log.c\nindex e464b30af4..d027ce1e0b 100644\n--- a/builtin/log.c\n+++ b/builtin/log.c\n@@ -613,7 +613,7 @@ static int show_blob_object(const struct object_id *oid, struct rev_info *rev, c\n \n static int show_tag_object(const struct object_id *oid, struct rev_info *rev)\n {\n-\tunsigned long size;\n+\tsize_t size;\n \tenum object_type type;\n \tchar *buf = odb_read_object(the_repository->objects, oid, &type, &size);\n \tunsigned long offset = 0;\ndiff --git a/builtin/ls-files.c b/builtin/ls-files.c\nindex 12d5d828ff..f30507215a 100644\n--- a/builtin/ls-files.c\n+++ b/builtin/ls-files.c\n@@ -256,7 +256,7 @@ static void expand_objectsize(struct repository *repo, struct strbuf *line,\n \tsize_t len;\n \n \tif (type == OBJ_BLOB) {\n-\t\tunsigned long size;\n+\t\tsize_t size;\n \t\tif (odb_read_object_info(repo->objects, oid, &size) < 0)\n \t\t\tdie(_(\"could not get object info about '%s'\"),\n \t\t\t    oid_to_hex(oid));\ndiff --git a/builtin/ls-tree.c b/builtin/ls-tree.c\nindex 57846911ce..46edaffc2e 100644\n--- a/builtin/ls-tree.c\n+++ b/builtin/ls-tree.c\n@@ -32,7 +32,7 @@ static void expand_objectsize(struct strbuf *line, const struct object_id *oid,\n \tsize_t len;\n \n \tif (type == OBJ_BLOB) {\n-\t\tunsigned long size;\n+\t\tsize_t size;\n \t\tif (odb_read_object_info(the_repository->objects, oid, &size) < 0)\n \t\t\tdie(_(\"could not get object info about '%s'\"),\n \t\t\t    oid_to_hex(oid));\n@@ -220,7 +220,7 @@ static int show_tree_long(const struct object_id *oid, struct strbuf *base,\n \t\treturn early;\n \n \tif (type == OBJ_BLOB) {\n-\t\tunsigned long size;\n+\t\tsize_t size;\n \t\tif (odb_read_object_info(the_repository->objects, oid, &size) == OBJ_BAD)\n \t\t\txsnprintf(size_text, sizeof(size_text), \"BAD\");\n \t\telse\ndiff --git a/builtin/merge-tree.c b/builtin/merge-tree.c\nindex 312b595d1e..49f41e520f 100644\n--- a/builtin/merge-tree.c\n+++ b/builtin/merge-tree.c\n@@ -69,7 +69,7 @@ static const char *explanation(struct merge_list *entry)\n \treturn \"removed in remote\";\n }\n \n-static void *result(struct merge_list *entry, unsigned long *size)\n+static void *result(struct merge_list *entry, size_t *size)\n {\n \tenum object_type type;\n \tstruct blob *base, *our, *their;\n@@ -96,7 +96,7 @@ static void *result(struct merge_list *entry, unsigned long *size)\n \t\t\t   base, our, their, size);\n }\n \n-static void *origin(struct merge_list *entry, unsigned long *size)\n+static void *origin(struct merge_list *entry, size_t *size)\n {\n \tenum object_type type;\n \twhile (entry) {\n@@ -119,7 +119,7 @@ static int show_outf(void *priv UNUSED, mmbuffer_t *mb, int nbuf)\n \n static void show_diff(struct merge_list *entry)\n {\n-\tunsigned long size;\n+\tsize_t size;\n \tmmfile_t src, dst;\n \txpparam_t xpp;\n \txdemitconf_t xecfg;\ndiff --git a/builtin/mktag.c b/builtin/mktag.c\nindex f40264a878..37c17e6beb 100644\n--- a/builtin/mktag.c\n+++ b/builtin/mktag.c\n@@ -50,7 +50,7 @@ static int verify_object_in_tag(struct object_id *tagged_oid, int *tagged_type)\n {\n \tint ret;\n \tenum object_type type;\n-\tunsigned long size;\n+\tsize_t size;\n \tvoid *buffer;\n \tconst struct object_id *repl;\n \ndiff --git a/builtin/notes.c b/builtin/notes.c\nindex 9af602bdd7..962df867c8 100644\n--- a/builtin/notes.c\n+++ b/builtin/notes.c\n@@ -150,7 +150,7 @@ static int list_each_note(const struct object_id *object_oid,\n \n static void copy_obj_to_fd(int fd, const struct object_id *oid)\n {\n-\tunsigned long size;\n+\tsize_t size;\n \tenum object_type type;\n \tchar *buf = odb_read_object(the_repository->objects, oid, &type, &size);\n \tif (buf) {\n@@ -313,7 +313,7 @@ static int parse_reuse_arg(const struct option *opt, const char *arg, int unset)\n \tchar *value;\n \tstruct object_id object;\n \tenum object_type type;\n-\tunsigned long len;\n+\tsize_t len;\n \n \tBUG_ON_OPT_NEG(unset);\n \n@@ -721,7 +721,7 @@ static int append_edit(int argc, const char **argv, const char *prefix,\n \n \tif (note && !edit) {\n \t\t/* Append buf to previous note contents */\n-\t\tunsigned long size;\n+\t\tsize_t size;\n \t\tenum object_type type;\n \t\tstruct strbuf buf = STRBUF_INIT;\n \t\tchar *prev_buf = odb_read_object(the_repository->objects, note, &type, &size);\ndiff --git a/builtin/pack-objects.c b/builtin/pack-objects.c\nindex 961d547ef2..b5092d97ee 100644\n--- a/builtin/pack-objects.c\n+++ b/builtin/pack-objects.c\n@@ -356,14 +356,17 @@ static void *get_delta(struct object_entry *entry)\n \tunsigned long size, base_size, delta_size;\n \tvoid *buf, *base_buf, *delta_buf;\n \tenum object_type type;\n+\tsize_t size_st = 0, base_size_st = 0;\n \n \tbuf = odb_read_object(the_repository->objects, &entry->idx.oid,\n-\t\t\t      &type, &size);\n+\t\t\t      &type, &size_st);\n+\tsize = cast_size_t_to_ulong(size_st);\n \tif (!buf)\n \t\tdie(_(\"unable to read %s\"), oid_to_hex(&entry->idx.oid));\n \tbase_buf = odb_read_object(the_repository->objects,\n \t\t\t\t   &DELTA(entry)->idx.oid, &type,\n-\t\t\t\t   &base_size);\n+\t\t\t\t   &base_size_st);\n+\tbase_size = cast_size_t_to_ulong(base_size_st);\n \tif (!base_buf)\n \t\tdie(\"unable to read %s\",\n \t\t    oid_to_hex(&DELTA(entry)->idx.oid));\n@@ -528,9 +531,11 @@ static unsigned long write_no_reuse_object(struct hashfile *f, struct object_ent\n \t\t\ttype = st->type;\n \t\t\tsize = st->size;\n \t\t} else {\n+\t\t\tsize_t size_st = 0;\n \t\t\tbuf = odb_read_object(the_repository->objects,\n \t\t\t\t\t      &entry->idx.oid, &type,\n-\t\t\t\t\t      &size);\n+\t\t\t\t\t      &size_st);\n+\t\t\tsize = cast_size_t_to_ulong(size_st);\n \t\t\tif (!buf)\n \t\t\t\tdie(_(\"unable to read %s\"),\n \t\t\t\t    oid_to_hex(&entry->idx.oid));\n@@ -1937,6 +1942,7 @@ static struct pbase_tree_cache *pbase_tree_get(const struct object_id *oid)\n \tstruct pbase_tree_cache *ent, *nent;\n \tvoid *data;\n \tunsigned long size;\n+\tsize_t size_st = 0;\n \tenum object_type type;\n \tint neigh;\n \tint my_ix = pbase_tree_cache_ix(oid);\n@@ -1964,7 +1970,8 @@ static struct pbase_tree_cache *pbase_tree_get(const struct object_id *oid)\n \t/* Did not find one.  Either we got a bogus request or\n \t * we need to read and perhaps cache.\n \t */\n-\tdata = odb_read_object(the_repository->objects, oid, &type, &size);\n+\tdata = odb_read_object(the_repository->objects, oid, &type, &size_st);\n+\tsize = cast_size_t_to_ulong(size_st);\n \tif (!data)\n \t\treturn NULL;\n \tif (type != OBJ_TREE) {\n@@ -2119,13 +2126,15 @@ static void add_preferred_base(struct object_id *oid)\n \tstruct pbase_tree *it;\n \tvoid *data;\n \tunsigned long size;\n+\tsize_t size_st = 0;\n \tstruct object_id tree_oid;\n \n \tif (window <= num_preferred_base++)\n \t\treturn;\n \n \tdata = odb_read_object_peeled(the_repository->objects, oid,\n-\t\t\t\t      OBJ_TREE, &size, &tree_oid);\n+\t\t\t\t      OBJ_TREE, &size_st, &tree_oid);\n+\tsize = cast_size_t_to_ulong(size_st);\n \tif (!data)\n \t\treturn;\n \n@@ -2237,7 +2246,7 @@ static void prefetch_to_pack(uint32_t object_index_start) {\n \n static void check_object(struct object_entry *entry, uint32_t object_index)\n {\n-\tunsigned long canonical_size;\n+\tsize_t canonical_size;\n \tenum object_type type;\n \tstruct object_info oi = {.typep = &type, .sizep = &canonical_size};\n \n@@ -2436,7 +2445,7 @@ static void drop_reused_delta(struct object_entry *entry)\n \tunsigned *idx = &to_pack.objects[entry->delta_idx - 1].delta_child_idx;\n \tstruct object_info oi = OBJECT_INFO_INIT;\n \tenum object_type type;\n-\tunsigned long size;\n+\tsize_t size;\n \n \twhile (*idx) {\n \t\tstruct object_entry *oe = &to_pack.objects[*idx - 1];\n@@ -2748,7 +2757,7 @@ size_t oe_get_size_slow(struct packing_data *pack,\n \tsize_t size;\n \n \tif (e->type_ != OBJ_OFS_DELTA && e->type_ != OBJ_REF_DELTA) {\n-\t\tunsigned long sz;\n+\t\tsize_t sz;\n \t\tpacking_data_lock(&to_pack);\n \t\tif (odb_read_object_info(the_repository->objects,\n \t\t\t\t\t &e->idx.oid, &sz) < 0)\n@@ -2833,10 +2842,12 @@ static int try_delta(struct unpacked *trg, struct unpacked *src,\n \n \t/* Load data if not already done */\n \tif (!trg->data) {\n+\t\tsize_t sz_st = 0;\n \t\tpacking_data_lock(&to_pack);\n \t\ttrg->data = odb_read_object(the_repository->objects,\n \t\t\t\t\t    &trg_entry->idx.oid, &type,\n-\t\t\t\t\t    &sz);\n+\t\t\t\t\t    &sz_st);\n+\t\tsz = cast_size_t_to_ulong(sz_st);\n \t\tpacking_data_unlock(&to_pack);\n \t\tif (!trg->data)\n \t\t\tdie(_(\"object %s cannot be read\"),\n@@ -2848,10 +2859,12 @@ static int try_delta(struct unpacked *trg, struct unpacked *src,\n \t\t*mem_usage += sz;\n \t}\n \tif (!src->data) {\n+\t\tsize_t sz_st = 0;\n \t\tpacking_data_lock(&to_pack);\n \t\tsrc->data = odb_read_object(the_repository->objects,\n \t\t\t\t\t    &src_entry->idx.oid, &type,\n-\t\t\t\t\t    &sz);\n+\t\t\t\t\t    &sz_st);\n+\t\tsz = cast_size_t_to_ulong(sz_st);\n \t\tpacking_data_unlock(&to_pack);\n \t\tif (!src->data) {\n \t\t\tif (src_entry->preferred_base) {\ndiff --git a/builtin/repo.c b/builtin/repo.c\nindex 71a5c1c29c..69f3626467 100644\n--- a/builtin/repo.c\n+++ b/builtin/repo.c\n@@ -784,13 +784,14 @@ static int count_objects(const char *path UNUSED, struct oid_array *oids,\n \tfor (size_t i = 0; i < oids->nr; i++) {\n \t\tstruct object_info oi = OBJECT_INFO_INIT;\n \t\tunsigned long inflated;\n+\t\tsize_t inflated_st = 0;\n \t\tstruct commit *commit;\n \t\tstruct object *obj;\n \t\tvoid *content;\n \t\toff_t disk;\n \t\tint eaten;\n \n-\t\toi.sizep = &inflated;\n+\t\toi.sizep = &inflated_st;\n \t\toi.disk_sizep = &disk;\n \t\toi.contentp = &content;\n \n@@ -798,6 +799,7 @@ static int count_objects(const char *path UNUSED, struct oid_array *oids,\n \t\t\t\t\t\t  OBJECT_INFO_SKIP_FETCH_OBJECT |\n \t\t\t\t\t\t  OBJECT_INFO_QUICK) < 0)\n \t\t\tcontinue;\n+\t\tinflated = cast_size_t_to_ulong(inflated_st);\n \n \t\tobj = parse_object_buffer(the_repository, &oids->oid[i], type,\n \t\t\t\t\t  inflated, content, &eaten);\ndiff --git a/builtin/tag.c b/builtin/tag.c\nindex d51c2e3349..06c125b53c 100644\n--- a/builtin/tag.c\n+++ b/builtin/tag.c\n@@ -238,7 +238,7 @@ static int git_tag_config(const char *var, const char *value,\n \n static void write_tag_body(int fd, const struct object_id *oid)\n {\n-\tunsigned long size;\n+\tsize_t size;\n \tenum object_type type;\n \tchar *buf, *sp, *orig;\n \tstruct strbuf payload = STRBUF_INIT;\n@@ -388,7 +388,7 @@ static void create_reflog_msg(const struct object_id *oid, struct strbuf *sb)\n \tenum object_type type;\n \tstruct commit *c;\n \tchar *buf;\n-\tunsigned long size;\n+\tsize_t size;\n \tint subject_len = 0;\n \tconst char *subject_start;\n \ndiff --git a/builtin/unpack-file.c b/builtin/unpack-file.c\nindex 87877a9fab..387389ed49 100644\n--- a/builtin/unpack-file.c\n+++ b/builtin/unpack-file.c\n@@ -12,7 +12,7 @@ static char *create_temp_file(struct object_id *oid)\n \tstatic char path[50];\n \tvoid *buf;\n \tenum object_type type;\n-\tunsigned long size;\n+\tsize_t size;\n \tint fd;\n \n \tbuf = odb_read_object(the_repository->objects, oid, &type, &size);\ndiff --git a/builtin/unpack-objects.c b/builtin/unpack-objects.c\nindex e7a50c493c..f3849bb654 100644\n--- a/builtin/unpack-objects.c\n+++ b/builtin/unpack-objects.c\n@@ -231,7 +231,7 @@ static int check_object(struct object *obj, enum object_type type,\n \t\tdie(\"object type mismatch\");\n \n \tif (!(obj->flags & FLAG_OPEN)) {\n-\t\tunsigned long size;\n+\t\tsize_t size;\n \t\tint type = odb_read_object_info(the_repository->objects, &obj->oid, &size);\n \t\tif (type != obj->type || type <= 0)\n \t\t\tdie(\"object of unexpected type\");\n@@ -436,6 +436,7 @@ static void unpack_delta_entry(enum object_type type, unsigned long delta_size,\n {\n \tvoid *delta_data, *base;\n \tunsigned long base_size;\n+\tsize_t base_size_st = 0;\n \tstruct object_id base_oid;\n \n \tif (type == OBJ_REF_DELTA) {\n@@ -512,7 +513,8 @@ static void unpack_delta_entry(enum object_type type, unsigned long delta_size,\n \t\treturn;\n \n \tbase = odb_read_object(the_repository->objects, &base_oid,\n-\t\t\t       &type, &base_size);\n+\t\t\t       &type, &base_size_st);\n+\tbase_size = cast_size_t_to_ulong(base_size_st);\n \tif (!base) {\n \t\terror(\"failed to read delta-pack base object %s\",\n \t\t      oid_to_hex(&base_oid));\ndiff --git a/bundle.c b/bundle.c\nindex 42327f9739..fd2db2c837 100644\n--- a/bundle.c\n+++ b/bundle.c\n@@ -296,7 +296,7 @@ int list_bundle_refs(struct bundle_header *header, int argc, const char **argv)\n \n static int is_tag_in_date_range(struct object *tag, struct rev_info *revs)\n {\n-\tunsigned long size;\n+\tsize_t size;\n \tenum object_type type;\n \tchar *buf = NULL, *line, *lineend;\n \ttimestamp_t date;\ndiff --git a/combine-diff.c b/combine-diff.c\nindex b799862068..3ce71db8bb 100644\n--- a/combine-diff.c\n+++ b/combine-diff.c\n@@ -325,7 +325,9 @@ static char *grab_blob(struct repository *r,\n \t\t*size = fill_textconv(r, textconv, df, &blob);\n \t\tfree_filespec(df);\n \t} else {\n-\t\tblob = odb_read_object(r->objects, oid, &type, size);\n+\t\tsize_t size_st = 0;\n+\t\tblob = odb_read_object(r->objects, oid, &type, &size_st);\n+\t\t*size = cast_size_t_to_ulong(size_st);\n \t\tif (!blob)\n \t\t\tdie(_(\"unable to read %s\"), oid_to_hex(oid));\n \t\tif (type != OBJ_BLOB)\ndiff --git a/commit.c b/commit.c\nindex fd8723502e..7950effc58 100644\n--- a/commit.c\n+++ b/commit.c\n@@ -395,7 +395,7 @@ const void *repo_get_commit_buffer(struct repository *r,\n \tconst void *ret = get_cached_commit_buffer(r, commit, sizep);\n \tif (!ret) {\n \t\tenum object_type type;\n-\t\tunsigned long size;\n+\t\tsize_t size;\n \t\tret = odb_read_object(r->objects, &commit->object.oid, &type, &size);\n \t\tif (!ret)\n \t\t\tdie(\"cannot read commit object %s\",\n@@ -404,7 +404,7 @@ const void *repo_get_commit_buffer(struct repository *r,\n \t\t\tdie(\"expected commit for %s, got %s\",\n \t\t\t    oid_to_hex(&commit->object.oid), type_name(type));\n \t\tif (sizep)\n-\t\t\t*sizep = size;\n+\t\t\t*sizep = cast_size_t_to_ulong(size);\n \t}\n \treturn ret;\n }\n@@ -437,7 +437,7 @@ static inline void set_commit_tree(struct commit *c, struct tree *t)\n static void load_tree_from_commit_contents(struct repository *r, struct commit *commit)\n {\n \tenum object_type type;\n-\tunsigned long size;\n+\tsize_t size;\n \tchar *buf;\n \tconst char *p;\n \tstruct object_id tree_oid;\n@@ -604,7 +604,7 @@ int repo_parse_commit_internal(struct repository *r,\n {\n \tenum object_type type;\n \tvoid *buffer;\n-\tunsigned long size;\n+\tsize_t size;\n \tstruct object_info oi = {\n \t\t.typep = &type,\n \t\t.sizep = &size,\n@@ -1313,7 +1313,7 @@ static void handle_signed_tag(const struct commit *parent, struct commit_extra_h\n \tstruct merge_remote_desc *desc;\n \tstruct commit_extra_header *mergetag;\n \tchar *buf;\n-\tunsigned long size;\n+\tsize_t size;\n \tenum object_type type;\n \tstruct strbuf payload = STRBUF_INIT;\n \tstruct strbuf signature = STRBUF_INIT;\ndiff --git a/config.c b/config.c\nindex a1b92fe083..21b231052c 100644\n--- a/config.c\n+++ b/config.c\n@@ -1442,7 +1442,7 @@ int git_config_from_blob_oid(config_fn_t fn,\n {\n \tenum object_type type;\n \tchar *buf;\n-\tunsigned long size;\n+\tsize_t size;\n \tint ret;\n \n \tbuf = odb_read_object(repo->objects, oid, &type, &size);\ndiff --git a/diff.c b/diff.c\nindex 5a584fa1d5..816b89dc6c 100644\n--- a/diff.c\n+++ b/diff.c\n@@ -4594,8 +4594,9 @@ int diff_populate_filespec(struct repository *r,\n \t\t}\n \t}\n \telse {\n+\t\tsize_t size_st = 0;\n \t\tstruct object_info info = {\n-\t\t\t.sizep = &s->size\n+\t\t\t.sizep = &size_st\n \t\t};\n \n \t\tif (!(size_only || check_binary))\n@@ -4617,6 +4618,7 @@ int diff_populate_filespec(struct repository *r,\n \t\t\tdie(\"unable to read %s\", oid_to_hex(&s->oid));\n \n object_read:\n+\t\ts->size = cast_size_t_to_ulong(size_st);\n \t\tif (size_only || check_binary) {\n \t\t\tif (size_only)\n \t\t\t\treturn 0;\n@@ -4631,6 +4633,7 @@ object_read:\n \t\t\tif (odb_read_object_info_extended(r->objects, &s->oid, &info,\n \t\t\t\t\t\t\t  OBJECT_INFO_LOOKUP_REPLACE))\n \t\t\t\tdie(\"unable to read %s\", oid_to_hex(&s->oid));\n+\t\t\ts->size = cast_size_t_to_ulong(size_st);\n \t\t}\n \t\ts->should_free = 1;\n \t}\ndiff --git a/dir.c b/dir.c\nindex 33c81c256e..b6764d98a7 100644\n--- a/dir.c\n+++ b/dir.c\n@@ -324,7 +324,7 @@ static int do_read_blob(const struct object_id *oid, struct oid_stat *oid_stat,\n \t\t\tsize_t *size_out, char **data_out)\n {\n \tenum object_type type;\n-\tunsigned long sz;\n+\tsize_t sz;\n \tchar *data;\n \n \t*size_out = 0;\ndiff --git a/entry.c b/entry.c\nindex 7817aee362..c444fe5a10 100644\n--- a/entry.c\n+++ b/entry.c\n@@ -92,11 +92,9 @@ static int create_file(const char *path, unsigned int mode)\n void *read_blob_entry(const struct cache_entry *ce, size_t *size)\n {\n \tenum object_type type;\n-\tunsigned long ul;\n \tvoid *blob_data = odb_read_object(the_repository->objects, &ce->oid,\n-\t\t\t\t\t  &type, &ul);\n+\t\t\t\t\t  &type, size);\n \n-\t*size = ul;\n \tif (blob_data) {\n \t\tif (type == OBJ_BLOB)\n \t\t\treturn blob_data;\ndiff --git a/fmt-merge-msg.c b/fmt-merge-msg.c\nindex 45d8b20e97..14441f23ae 100644\n--- a/fmt-merge-msg.c\n+++ b/fmt-merge-msg.c\n@@ -528,11 +528,11 @@ static void fmt_merge_msg_sigs(struct strbuf *out)\n \tfor (i = 0; i < origins.nr; i++) {\n \t\tstruct object_id *oid = origins.items[i].util;\n \t\tenum object_type type;\n-\t\tunsigned long size;\n+\t\tsize_t size;\n \t\tchar *buf = odb_read_object(the_repository->objects, oid,\n \t\t\t\t\t    &type, &size);\n \t\tchar *origbuf = buf;\n-\t\tunsigned long len = size;\n+\t\tsize_t len = size;\n \t\tstruct signature_check sigc = { NULL };\n \t\tstruct strbuf payload = STRBUF_INIT, sig = STRBUF_INIT;\n \ndiff --git a/fsck.c b/fsck.c\nindex b4ffee6a04..94c8651c7d 100644\n--- a/fsck.c\n+++ b/fsck.c\n@@ -1328,7 +1328,7 @@ static int fsck_blobs(struct oidset *blobs_found, struct oidset *blobs_done,\n \toidset_iter_init(blobs_found, &iter);\n \twhile ((oid = oidset_iter_next(&iter))) {\n \t\tenum object_type type;\n-\t\tunsigned long size;\n+\t\tsize_t size;\n \t\tchar *buf;\n \n \t\tif (oidset_contains(blobs_done, oid))\ndiff --git a/grep.c b/grep.c\nindex a54e5d86a9..1d75d31421 100644\n--- a/grep.c\n+++ b/grep.c\n@@ -1931,9 +1931,11 @@ void grep_source_clear_data(struct grep_source *gs)\n static int grep_source_load_oid(struct grep_source *gs)\n {\n \tenum object_type type;\n+\tsize_t size_st = 0;\n \n \tgs->buf = odb_read_object(gs->repo->objects, gs->identifier,\n-\t\t\t\t  &type, &gs->size);\n+\t\t\t\t  &type, &size_st);\n+\tgs->size = cast_size_t_to_ulong(size_st);\n \tif (!gs->buf)\n \t\treturn error(_(\"'%s': unable to read %s\"),\n \t\t\t     gs->name,\ndiff --git a/http-push.c b/http-push.c\nindex 520d6c3b6a..c61d9f7e02 100644\n--- a/http-push.c\n+++ b/http-push.c\n@@ -365,7 +365,7 @@ static void start_put(struct transfer_request *request)\n \tenum object_type type;\n \tchar hdr[50];\n \tvoid *unpacked;\n-\tunsigned long len;\n+\tsize_t len;\n \tint hdrlen;\n \tssize_t size;\n \tgit_zstream stream;\ndiff --git a/list-objects-filter.c b/list-objects-filter.c\nindex 78316e7f90..c912ff3079 100644\n--- a/list-objects-filter.c\n+++ b/list-objects-filter.c\n@@ -280,7 +280,7 @@ static enum list_objects_filter_result filter_blobs_limit(\n \tvoid *filter_data_)\n {\n \tstruct filter_blobs_limit_data *filter_data = filter_data_;\n-\tunsigned long object_length;\n+\tsize_t object_length;\n \tenum object_type t;\n \n \tswitch (filter_situation) {\ndiff --git a/mailmap.c b/mailmap.c\nindex 3b2691781d..72b639e602 100644\n--- a/mailmap.c\n+++ b/mailmap.c\n@@ -186,7 +186,7 @@ int read_mailmap_blob(struct repository *repo, struct string_list *map,\n {\n \tstruct object_id oid;\n \tchar *buf;\n-\tunsigned long size;\n+\tsize_t size;\n \tenum object_type type;\n \n \tif (!name)\ndiff --git a/match-trees.c b/match-trees.c\nindex 4216933d06..2a43c0fa1a 100644\n--- a/match-trees.c\n+++ b/match-trees.c\n@@ -61,7 +61,7 @@ static void *fill_tree_desc_strict(struct repository *r,\n {\n \tvoid *buffer;\n \tenum object_type type;\n-\tunsigned long size;\n+\tsize_t size;\n \n \tbuffer = odb_read_object(r->objects, hash, &type, &size);\n \tif (!buffer)\n@@ -186,7 +186,7 @@ static int splice_tree(struct repository *r,\n \tchar *subpath;\n \tint toplen;\n \tchar *buf;\n-\tunsigned long sz;\n+\tsize_t sz;\n \tstruct tree_desc desc;\n \tunsigned char *rewrite_here;\n \tconst struct object_id *rewrite_with;\ndiff --git a/merge-blobs.c b/merge-blobs.c\nindex 6fc2799417..16a75bd1e3 100644\n--- a/merge-blobs.c\n+++ b/merge-blobs.c\n@@ -9,7 +9,7 @@\n static int fill_mmfile_blob(mmfile_t *f, struct blob *obj)\n {\n \tvoid *buf;\n-\tunsigned long size;\n+\tsize_t size;\n \tenum object_type type;\n \n \tbuf = odb_read_object(the_repository->objects, &obj->object.oid,\n@@ -35,7 +35,7 @@ static void *three_way_filemerge(struct index_state *istate,\n \t\t\t\t mmfile_t *base,\n \t\t\t\t mmfile_t *our,\n \t\t\t\t mmfile_t *their,\n-\t\t\t\t unsigned long *size)\n+\t\t\t\t size_t *size)\n {\n \tenum ll_merge_result merge_status;\n \tmmbuffer_t res;\n@@ -61,7 +61,7 @@ static void *three_way_filemerge(struct index_state *istate,\n \n void *merge_blobs(struct index_state *istate, const char *path,\n \t\t  struct blob *base, struct blob *our,\n-\t\t  struct blob *their, unsigned long *size)\n+\t\t  struct blob *their, size_t *size)\n {\n \tvoid *res = NULL;\n \tmmfile_t f1, f2, common;\ndiff --git a/merge-blobs.h b/merge-blobs.h\nindex 13cf9669e5..5797517a06 100644\n--- a/merge-blobs.h\n+++ b/merge-blobs.h\n@@ -6,6 +6,6 @@ struct index_state;\n \n void *merge_blobs(struct index_state *, const char *,\n \t\t  struct blob *, struct blob *,\n-\t\t  struct blob *, unsigned long *);\n+\t\t  struct blob *, size_t *);\n \n #endif /* MERGE_BLOBS_H */\ndiff --git a/merge-ort.c b/merge-ort.c\nindex 544be9e466..4f6273bd51 100644\n--- a/merge-ort.c\n+++ b/merge-ort.c\n@@ -3716,7 +3716,7 @@ static int read_oid_strbuf(struct merge_options *opt,\n {\n \tvoid *buf;\n \tenum object_type type;\n-\tunsigned long size;\n+\tsize_t size;\n \tbuf = odb_read_object(opt->repo->objects, oid, &type, &size);\n \tif (!buf) {\n \t\tpath_msg(opt, ERROR_OBJECT_READ_FAILED, 0,\ndiff --git a/notes-cache.c b/notes-cache.c\nindex bf5bb1f6c1..74cef802bd 100644\n--- a/notes-cache.c\n+++ b/notes-cache.c\n@@ -82,7 +82,7 @@ char *notes_cache_get(struct notes_cache *c, struct object_id *key_oid,\n \tconst struct object_id *value_oid;\n \tenum object_type type;\n \tchar *value;\n-\tunsigned long size;\n+\tsize_t size;\n \n \tvalue_oid = get_note(&c->tree, key_oid);\n \tif (!value_oid)\ndiff --git a/notes-merge.c b/notes-merge.c\nindex b9322abbcb..118cad2518 100644\n--- a/notes-merge.c\n+++ b/notes-merge.c\n@@ -339,7 +339,7 @@ static void write_note_to_worktree(const struct object_id *obj,\n \t\t\t\t   const struct object_id *note)\n {\n \tenum object_type type;\n-\tunsigned long size;\n+\tsize_t size;\n \tvoid *buf = odb_read_object(the_repository->objects, note, &type, &size);\n \n \tif (!buf)\ndiff --git a/notes.c b/notes.c\nindex 8f315e2a00..ec9c2cb150 100644\n--- a/notes.c\n+++ b/notes.c\n@@ -811,7 +811,8 @@ int combine_notes_concatenate(struct object_id *cur_oid,\n \t\t\t      const struct object_id *new_oid)\n {\n \tchar *cur_msg = NULL, *new_msg = NULL, *buf;\n-\tunsigned long cur_len, new_len, buf_len;\n+\tunsigned long buf_len;\n+\tsize_t cur_len, new_len;\n \tenum object_type cur_type, new_type;\n \tint ret;\n \n@@ -875,7 +876,7 @@ static int string_list_add_note_lines(struct string_list *list,\n \t\t\t\t      const struct object_id *oid)\n {\n \tchar *data;\n-\tunsigned long len;\n+\tsize_t len;\n \tenum object_type t;\n \n \tif (is_null_oid(oid))\n@@ -1282,7 +1283,8 @@ static void format_note(struct notes_tree *t, const struct object_id *object_oid\n \tstatic const char utf8[] = \"utf-8\";\n \tconst struct object_id *oid;\n \tchar *msg, *msg_p;\n-\tunsigned long linelen, msglen;\n+\tunsigned long linelen;\n+\tsize_t msglen;\n \tenum object_type type;\n \n \tif (!t)\ndiff --git a/object-file.c b/object-file.c\nindex bce941874e..3a21c14027 100644\n--- a/object-file.c\n+++ b/object-file.c\n@@ -300,7 +300,7 @@ int parse_loose_header(const char *hdr, struct object_info *oi)\n \t}\n \n \tif (oi->sizep)\n-\t\t*oi->sizep = cast_size_t_to_ulong(size);\n+\t\t*oi->sizep = size;\n \n \t/*\n \t * The length must be followed by a zero byte\n@@ -931,7 +931,7 @@ int force_object_loose(struct odb_source *source,\n \tstruct odb_source_files *files = odb_source_files_downcast(source);\n \tconst struct git_hash_algo *compat = source->odb->repo->compat_hash_algo;\n \tvoid *buf;\n-\tunsigned long len;\n+\tsize_t len;\n \tstruct object_info oi = OBJECT_INFO_INIT;\n \tstruct object_id compat_oid;\n \tenum object_type type;\n@@ -1614,7 +1614,7 @@ int read_loose_object(struct repository *repo,\n \tunsigned long mapsize;\n \tgit_zstream stream;\n \tchar hdr[MAX_HEADER_LEN];\n-\tunsigned long *size = oi->sizep;\n+\tsize_t *size = oi->sizep;\n \n \tfd = git_open(path);\n \tif (fd >= 0)\ndiff --git a/object.c b/object.c\nindex 465902ecc6..23b84aa7e2 100644\n--- a/object.c\n+++ b/object.c\n@@ -325,7 +325,7 @@ struct object *parse_object_with_flags(struct repository *r,\n {\n \tint skip_hash = !!(flags & PARSE_OBJECT_SKIP_HASH_CHECK);\n \tint discard_tree = !!(flags & PARSE_OBJECT_DISCARD_TREE);\n-\tunsigned long size;\n+\tsize_t size;\n \tenum object_type type;\n \tint eaten;\n \tconst struct object_id *repl = lookup_replace_object(r, oid);\ndiff --git a/odb.c b/odb.c\nindex 965ef68e4e..7d555be09f 100644\n--- a/odb.c\n+++ b/odb.c\n@@ -625,7 +625,7 @@ static int oid_object_info_convert(struct repository *r,\n \tenum object_type type;\n \tstruct object_id oid, delta_base_oid;\n \tstruct object_info new_oi, *oi;\n-\tunsigned long size;\n+\tsize_t size;\n \tvoid *content;\n \tint ret;\n \n@@ -716,7 +716,7 @@ int odb_read_object_info_extended(struct object_database *odb,\n /* returns enum object_type or negative */\n int odb_read_object_info(struct object_database *odb,\n \t\t\t const struct object_id *oid,\n-\t\t\t unsigned long *sizep)\n+\t\t\t size_t *sizep)\n {\n \tenum object_type type;\n \tstruct object_info oi = OBJECT_INFO_INIT;\n@@ -730,7 +730,7 @@ int odb_read_object_info(struct object_database *odb,\n }\n \n int odb_pretend_object(struct object_database *odb,\n-\t\t       void *buf, unsigned long len, enum object_type type,\n+\t\t       void *buf, size_t len, enum object_type type,\n \t\t       struct object_id *oid)\n {\n \thash_object_file(odb->repo->hash_algo, buf, len, type, oid);\n@@ -744,7 +744,7 @@ int odb_pretend_object(struct object_database *odb,\n void *odb_read_object(struct object_database *odb,\n \t\t      const struct object_id *oid,\n \t\t      enum object_type *type,\n-\t\t      unsigned long *size)\n+\t\t      size_t *size)\n {\n \tstruct object_info oi = OBJECT_INFO_INIT;\n \tunsigned flags = OBJECT_INFO_DIE_IF_CORRUPT | OBJECT_INFO_LOOKUP_REPLACE;\n@@ -762,12 +762,12 @@ void *odb_read_object(struct object_database *odb,\n void *odb_read_object_peeled(struct object_database *odb,\n \t\t\t     const struct object_id *oid,\n \t\t\t     enum object_type required_type,\n-\t\t\t     unsigned long *size,\n+\t\t\t     size_t *size,\n \t\t\t     struct object_id *actual_oid_return)\n {\n \tenum object_type type;\n \tvoid *buffer;\n-\tunsigned long isize;\n+\tsize_t isize;\n \tstruct object_id actual_oid;\n \n \toidcpy(&actual_oid, oid);\ndiff --git a/odb.h b/odb.h\nindex 73553ed5a7..e2f0bbad25 100644\n--- a/odb.h\n+++ b/odb.h\n@@ -228,12 +228,12 @@ struct odb_source *odb_add_to_alternates_memory(struct object_database *odb,\n void *odb_read_object(struct object_database *odb,\n \t\t      const struct object_id *oid,\n \t\t      enum object_type *type,\n-\t\t      unsigned long *size);\n+\t\t      size_t *size);\n \n void *odb_read_object_peeled(struct object_database *odb,\n \t\t\t     const struct object_id *oid,\n \t\t\t     enum object_type required_type,\n-\t\t\t     unsigned long *size,\n+\t\t\t     size_t *size,\n \t\t\t     struct object_id *oid_ret);\n \n /*\n@@ -245,13 +245,13 @@ void *odb_read_object_peeled(struct object_database *odb,\n  * that reference it.\n  */\n int odb_pretend_object(struct object_database *odb,\n-\t\t       void *buf, unsigned long len, enum object_type type,\n+\t\t       void *buf, size_t len, enum object_type type,\n \t\t       struct object_id *oid);\n \n struct object_info {\n \t/* Request */\n \tenum object_type *typep;\n-\tunsigned long *sizep;\n+\tsize_t *sizep;\n \toff_t *disk_sizep;\n \tstruct object_id *delta_base_oid;\n \tvoid **contentp;\n@@ -356,7 +356,7 @@ int odb_read_object_info_extended(struct object_database *odb,\n  */\n int odb_read_object_info(struct object_database *odb,\n \t\t\t const struct object_id *oid,\n-\t\t\t unsigned long *sizep);\n+\t\t\t size_t *sizep);\n \n enum odb_has_object_flags {\n \t/* Retry packed storage after checking packed and loose storage */\ndiff --git a/odb/source-loose.c b/odb/source-loose.c\nindex 7d7ea2fb84..66e6bb8d3f 100644\n--- a/odb/source-loose.c\n+++ b/odb/source-loose.c\n@@ -72,7 +72,7 @@ static int read_object_info_from_path(struct odb_source_loose *loose,\n \tvoid *map = NULL;\n \tgit_zstream stream, *stream_to_end = NULL;\n \tchar hdr[MAX_HEADER_LEN];\n-\tunsigned long size_scratch;\n+\tsize_t size_scratch;\n \tenum object_type type_scratch;\n \tstruct stat st;\n \n@@ -355,7 +355,6 @@ static int odb_source_loose_read_object_stream(struct odb_read_stream **out,\n \tstruct object_info oi = OBJECT_INFO_INIT;\n \tstruct odb_loose_read_stream *st;\n \tunsigned long mapsize;\n-\tunsigned long size_ul;\n \tvoid *mapped;\n \n \tmapped = odb_source_loose_map_object(loose, oid, &mapsize);\n@@ -379,18 +378,11 @@ static int odb_source_loose_read_object_stream(struct odb_read_stream **out,\n \t\tgoto error;\n \t}\n \n-\t/*\n-\t * object_info.sizep is unsigned long* (32-bit on Windows), but\n-\t * st->base.size is size_t (64-bit). Use temporary variable.\n-\t * Note: loose objects >4GB would still truncate here, but such\n-\t * large loose objects are uncommon (they'd normally be packed).\n-\t */\n-\toi.sizep = &size_ul;\n+\toi.sizep = &st->base.size;\n \toi.typep = &st->base.type;\n \n \tif (parse_loose_header(st->hdr, &oi) < 0 || st->base.type < 0)\n \t\tgoto error;\n-\tst->base.size = size_ul;\n \n \tst->mapped = mapped;\n \tst->mapsize = mapsize;\ndiff --git a/odb/streaming.c b/odb/streaming.c\nindex 7602a8d5d8..20531e864c 100644\n--- a/odb/streaming.c\n+++ b/odb/streaming.c\n@@ -157,26 +157,15 @@ static int open_istream_incore(struct odb_read_stream **out,\n \t\t.base.read = read_istream_incore,\n \t};\n \tstruct odb_incore_read_stream *st;\n-\tunsigned long size_ul;\n \tint ret;\n \n \toi.typep = &stream.base.type;\n-\t/*\n-\t * object_info.sizep is unsigned long* (32-bit on Windows), but\n-\t * stream.base.size is size_t (64-bit). We use a temporary variable\n-\t * because the types are incompatible. Note: this path still truncates\n-\t * for >4GB objects, but large objects should use pack streaming\n-\t * (packfile_store_read_object_stream) which handles size_t properly.\n-\t * This incore fallback is only used for small objects or when pack\n-\t * streaming is unavailable.\n-\t */\n-\toi.sizep = &size_ul;\n+\toi.sizep = &stream.base.size;\n \toi.contentp = (void **)&stream.buf;\n \tret = odb_read_object_info_extended(odb, oid, &oi,\n \t\t\t\t\t    OBJECT_INFO_DIE_IF_CORRUPT);\n \tif (ret)\n \t\treturn ret;\n-\tstream.base.size = size_ul;\n \n \tCALLOC_ARRAY(st, 1);\n \t*st = stream;\ndiff --git a/pack-bitmap.c b/pack-bitmap.c\nindex f9af8a96bd..e8a82945cc 100644\n--- a/pack-bitmap.c\n+++ b/pack-bitmap.c\n@@ -1856,7 +1856,7 @@ static void filter_bitmap_blob_none(struct bitmap_index *bitmap_git,\n static unsigned long get_size_by_pos(struct bitmap_index *bitmap_git,\n \t\t\t\t     uint32_t pos)\n {\n-\tunsigned long size;\n+\tsize_t size;\n \tstruct object_info oi = OBJECT_INFO_INIT;\n \n \toi.sizep = &size;\n@@ -1891,7 +1891,7 @@ static unsigned long get_size_by_pos(struct bitmap_index *bitmap_git,\n \t\t\tdie(_(\"unable to get size of %s\"), oid_to_hex(&obj->oid));\n \t}\n \n-\treturn size;\n+\treturn cast_size_t_to_ulong(size);\n }\n \n static void filter_bitmap_blob_limit(struct bitmap_index *bitmap_git,\ndiff --git a/packfile.c b/packfile.c\nindex c174982d10..78c389e6f3 100644\n--- a/packfile.c\n+++ b/packfile.c\n@@ -1607,13 +1607,10 @@ static int packed_object_info_with_index_pos(struct packed_git *p, off_t obj_off\n \t * a \"real\" type later if the caller is interested.\n \t */\n \tif (oi->contentp) {\n-\t\tsize_t size_st = 0;\n \t\t*oi->contentp = cache_or_unpack_entry(p->repo, p, obj_offset,\n-\t\t\t\t\t\t      &size_st, &type);\n+\t\t\t\t\t\t      oi->sizep, &type);\n \t\tif (!*oi->contentp)\n \t\t\ttype = OBJ_BAD;\n-\t\telse if (oi->sizep)\n-\t\t\t*oi->sizep = cast_size_t_to_ulong(size_st);\n \t} else if (oi->sizep || oi->typep || oi->delta_base_oid) {\n \t\ttype = unpack_object_header(p, &w_curs, &curpos, &size);\n \t}\n@@ -1633,7 +1630,7 @@ static int packed_object_info_with_index_pos(struct packed_git *p, off_t obj_off\n \t\t\t\tgoto out;\n \t\t\t}\n \t\t}\n-\t\t*oi->sizep = (unsigned long)size;\n+\t\t*oi->sizep = size;\n \t}\n \n \tif (oi->disk_sizep || (oi->mtimep && p->is_cruft)) {\n@@ -1919,7 +1916,6 @@ void *unpack_entry(struct repository *r, struct packed_git *p, off_t obj_offset,\n \t\t\tstruct object_id base_oid;\n \t\t\tif (!(offset_to_pack_pos(p, obj_offset, &pos))) {\n \t\t\t\tstruct object_info oi = OBJECT_INFO_INIT;\n-\t\t\t\tunsigned long bsz_ul = 0;\n \n \t\t\t\tnth_packed_object_id(&base_oid, p,\n \t\t\t\t\t\t     pack_pos_to_index(p, pos));\n@@ -1930,13 +1926,11 @@ void *unpack_entry(struct repository *r, struct packed_git *p, off_t obj_offset,\n \t\t\t\tmark_bad_packed_object(p, &base_oid);\n \n \t\t\t\toi.typep = &type;\n-\t\t\t\toi.sizep = &bsz_ul;\n+\t\t\t\toi.sizep = &base_size;\n \t\t\t\toi.contentp = &base;\n \t\t\t\tif (odb_read_object_info_extended(r->objects, &base_oid,\n \t\t\t\t\t\t\t\t  &oi, 0) < 0)\n \t\t\t\t\tbase = NULL;\n-\t\t\t\telse\n-\t\t\t\t\tbase_size = bsz_ul;\n \n \t\t\t\texternal_base = base;\n \t\t\t}\ndiff --git a/path-walk.c b/path-walk.c\nindex 94ff90bd15..edc8e736d7 100644\n--- a/path-walk.c\n+++ b/path-walk.c\n@@ -368,7 +368,7 @@ static int walk_path(struct path_walk_context *ctx,\n \t\tstruct oid_array filtered = OID_ARRAY_INIT;\n \n \t\tfor (size_t i = 0; i < list->oids.nr; i++) {\n-\t\t\tunsigned long size;\n+\t\t\tsize_t size;\n \n \t\t\tif (odb_read_object_info(ctx->repo->objects,\n \t\t\t\t\t\t &list->oids.oid[i],\ndiff --git a/protocol-caps.c b/protocol-caps.c\nindex 35072ed60b..8858ea4489 100644\n--- a/protocol-caps.c\n+++ b/protocol-caps.c\n@@ -50,7 +50,7 @@ static void send_info(struct repository *r, struct packet_writer *writer,\n \tfor_each_string_list_item (item, oid_str_list) {\n \t\tconst char *oid_str = item->string;\n \t\tstruct object_id oid;\n-\t\tunsigned long object_size;\n+\t\tsize_t object_size;\n \n \t\tif (get_oid_hex_algop(oid_str, &oid, r->hash_algo) < 0) {\n \t\t\tpacket_writer_error(\n@@ -66,7 +66,8 @@ static void send_info(struct repository *r, struct packet_writer *writer,\n \t\t\tif (odb_read_object_info(r->objects, &oid, &object_size) < 0) {\n \t\t\t\tstrbuf_addstr(&send_buffer, \" \");\n \t\t\t} else {\n-\t\t\t\tstrbuf_addf(&send_buffer, \" %lu\", object_size);\n+\t\t\t\tstrbuf_addf(&send_buffer, \" %\"PRIuMAX,\n+\t\t\t\t\t    (uintmax_t)object_size);\n \t\t\t}\n \t\t}\n \ndiff --git a/read-cache.c b/read-cache.c\nindex 21829102ae..21ca58beea 100644\n--- a/read-cache.c\n+++ b/read-cache.c\n@@ -250,7 +250,7 @@ static int ce_compare_link(const struct cache_entry *ce, size_t expected_size)\n {\n \tint match = -1;\n \tvoid *buffer;\n-\tunsigned long size;\n+\tsize_t size;\n \tenum object_type type;\n \tstruct strbuf sb = STRBUF_INIT;\n \n@@ -3462,7 +3462,7 @@ void *read_blob_data_from_index(struct index_state *istate,\n \t\t\t\tconst char *path, unsigned long *size)\n {\n \tint pos, len;\n-\tunsigned long sz;\n+\tsize_t sz;\n \tenum object_type type;\n \tvoid *data;\n \n@@ -3490,7 +3490,7 @@ void *read_blob_data_from_index(struct index_state *istate,\n \t\treturn NULL;\n \t}\n \tif (size)\n-\t\t*size = sz;\n+\t\t*size = cast_size_t_to_ulong(sz);\n \treturn data;\n }\n \ndiff --git a/ref-filter.c b/ref-filter.c\nindex 1da4c0e60d..8ba91c72a1 100644\n--- a/ref-filter.c\n+++ b/ref-filter.c\n@@ -86,7 +86,7 @@ struct ref_trailer_buf {\n static struct expand_data {\n \tstruct object_id oid;\n \tenum object_type type;\n-\tunsigned long size;\n+\tsize_t size;\n \toff_t disk_size;\n \tstruct object_id delta_base_oid;\n \tvoid *content;\ndiff --git a/reflog.c b/reflog.c\nindex 82337078d0..04edbe5670 100644\n--- a/reflog.c\n+++ b/reflog.c\n@@ -154,7 +154,7 @@ static int tree_is_complete(const struct object_id *oid)\n \n \tif (!tree->buffer) {\n \t\tenum object_type type;\n-\t\tunsigned long size;\n+\t\tsize_t size;\n \t\tvoid *data = odb_read_object(the_repository->objects, oid,\n \t\t\t\t\t     &type, &size);\n \t\tif (!data) {\ndiff --git a/rerere.c b/rerere.c\nindex 0296700f9f..068321b24f 100644\n--- a/rerere.c\n+++ b/rerere.c\n@@ -990,7 +990,7 @@ static int handle_cache(struct index_state *istate,\n \n \twhile (pos < istate->cache_nr) {\n \t\tenum object_type type;\n-\t\tunsigned long size;\n+\t\tsize_t size;\n \n \t\tce = istate->cache[pos++];\n \t\tif (ce_namelen(ce) != len || memcmp(ce->name, path, len))\ndiff --git a/submodule-config.c b/submodule-config.c\nindex a81897b4e0..f75997402a 100644\n--- a/submodule-config.c\n+++ b/submodule-config.c\n@@ -694,7 +694,7 @@ static const struct submodule *config_from(struct submodule_cache *cache,\n \t\tenum lookup_type lookup_type)\n {\n \tstruct strbuf rev = STRBUF_INIT;\n-\tunsigned long config_size;\n+\tsize_t config_size;\n \tchar *config = NULL;\n \tstruct object_id oid;\n \tenum object_type type;\ndiff --git a/t/helper/test-pack-deltas.c b/t/helper/test-pack-deltas.c\nindex c493b75e02..840797cf0d 100644\n--- a/t/helper/test-pack-deltas.c\n+++ b/t/helper/test-pack-deltas.c\n@@ -48,7 +48,8 @@ static void write_ref_delta(struct hashfile *f,\n \t\t\t    struct object_id *base)\n {\n \tunsigned char header[MAX_PACK_OBJECT_HEADER];\n-\tunsigned long size, base_size, delta_size, compressed_size, hdrlen;\n+\tunsigned long delta_size, compressed_size, hdrlen;\n+\tsize_t size, base_size;\n \tenum object_type type;\n \tvoid *base_buf, *delta_buf;\n \tvoid *buf = odb_read_object(the_repository->objects,\ndiff --git a/t/helper/test-partial-clone.c b/t/helper/test-partial-clone.c\nindex a7aab426d0..87c59108e0 100644\n--- a/t/helper/test-partial-clone.c\n+++ b/t/helper/test-partial-clone.c\n@@ -17,7 +17,7 @@ static void object_info(const char *gitdir, const char *oid_hex)\n {\n \tstruct repository r;\n \tstruct object_id oid;\n-\tunsigned long size;\n+\tsize_t size;\n \tstruct object_info oi = {.sizep = &size};\n \tconst char *p;\n \ndiff --git a/t/unit-tests/u-odb-inmemory.c b/t/unit-tests/u-odb-inmemory.c\nindex 482502ef4b..6844bfc37c 100644\n--- a/t/unit-tests/u-odb-inmemory.c\n+++ b/t/unit-tests/u-odb-inmemory.c\n@@ -20,7 +20,7 @@ static void cl_assert_object_info(struct odb_source_inmemory *source,\n \t\t\t\t  const char *expected_content)\n {\n \tenum object_type actual_type;\n-\tunsigned long actual_size;\n+\tsize_t actual_size;\n \tvoid *actual_content;\n \tstruct object_info oi = {\n \t\t.typep = &actual_type,\ndiff --git a/tag.c b/tag.c\nindex 2f12e51024..1a00ded6eb 100644\n--- a/tag.c\n+++ b/tag.c\n@@ -49,7 +49,7 @@ int gpg_verify_tag(struct repository *r, const struct object_id *oid,\n {\n \tenum object_type type;\n \tchar *buf;\n-\tunsigned long size;\n+\tsize_t size;\n \tint ret;\n \n \ttype = odb_read_object_info(r->objects, oid, NULL);\n@@ -207,7 +207,7 @@ int parse_tag(struct repository *r, struct tag *item)\n {\n \tenum object_type type;\n \tvoid *data;\n-\tunsigned long size;\n+\tsize_t size;\n \tint ret;\n \n \tif (item->object.parsed)\ndiff --git a/tree-walk.c b/tree-walk.c\nindex 7e1b956f27..a67f06b9eb 100644\n--- a/tree-walk.c\n+++ b/tree-walk.c\n@@ -87,7 +87,7 @@ void *fill_tree_descriptor(struct repository *r,\n \t\t\t   struct tree_desc *desc,\n \t\t\t   const struct object_id *oid)\n {\n-\tunsigned long size = 0;\n+\tsize_t size = 0;\n \tvoid *buf = NULL;\n \n \tif (oid) {\n@@ -610,7 +610,7 @@ int get_tree_entry(struct repository *r,\n {\n \tint retval;\n \tvoid *tree;\n-\tunsigned long size;\n+\tsize_t size;\n \tstruct object_id root;\n \n \ttree = odb_read_object_peeled(r->objects, tree_oid, OBJ_TREE, &size, &root);\n@@ -682,7 +682,7 @@ enum get_oid_result get_tree_entry_follow_symlinks(struct repository *r,\n \t\tif (!t.buffer) {\n \t\t\tvoid *tree;\n \t\t\tstruct object_id root;\n-\t\t\tunsigned long size;\n+\t\t\tsize_t size;\n \t\t\ttree = odb_read_object_peeled(r->objects, &current_tree_oid,\n \t\t\t\t\t\t      OBJ_TREE, &size, &root);\n \t\t\tif (!tree)\n@@ -778,6 +778,7 @@ enum get_oid_result get_tree_entry_follow_symlinks(struct repository *r,\n \t\t} else if (S_ISLNK(*mode)) {\n \t\t\t/* Follow a symlink */\n \t\t\tunsigned long link_len;\n+\t\t\tsize_t link_len_st = 0;\n \t\t\tsize_t len;\n \t\t\tchar *contents, *contents_start;\n \t\t\tstruct dir_state *parent;\n@@ -797,7 +798,8 @@ enum get_oid_result get_tree_entry_follow_symlinks(struct repository *r,\n \n \t\t\tcontents = odb_read_object(r->objects,\n \t\t\t\t\t\t   &current_tree_oid, &type,\n-\t\t\t\t\t\t   &link_len);\n+\t\t\t\t\t\t   &link_len_st);\n+\t\t\tlink_len = cast_size_t_to_ulong(link_len_st);\n \n \t\t\tif (!contents)\n \t\t\t\tgoto done;\ndiff --git a/tree.c b/tree.c\nindex d703ab97c8..53f7395e9f 100644\n--- a/tree.c\n+++ b/tree.c\n@@ -188,7 +188,7 @@ int repo_parse_tree_gently(struct repository *r, struct tree *item,\n {\n \t enum object_type type;\n \t void *buffer;\n-\t unsigned long size;\n+\t size_t size;\n \n \tif (item->object.parsed)\n \t\treturn 0;\ndiff --git a/xdiff-interface.c b/xdiff-interface.c\nindex 5ee2b96d0a..db6938689f 100644\n--- a/xdiff-interface.c\n+++ b/xdiff-interface.c\n@@ -179,7 +179,7 @@ int read_mmfile(mmfile_t *ptr, const char *filename)\n void read_mmblob(mmfile_t *ptr, struct object_database *odb,\n \t\t const struct object_id *oid)\n {\n-\tunsigned long size;\n+\tsize_t size;\n \tenum object_type type;\n \n \tif (is_null_oid(oid)) {\n-- \ngitgitgadget\n"},{"id":"545586","messageId":"xmqqldcfdf9n.fsf@gitster.g","threadId":"65750","inReplyTo":"pull.2137.v2.git.1781524349.gitgitgadget@gmail.com","subject":"Re: [PATCH v2 0/7] More work supporting objects larger than 4GB on Windows","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2026-06-15T14:55:48Z","receivedAt":"2026-06-15T14:55:50Z","isPatch":true,"body":"\"Johannes Schindelin via GitGitGadget\" <gitgitgadget@gmail.com>\nwrites:\n\n> This patch series tries to address the problems pointed out by the expensive\n> tests that now run in CI: t5608 and t7508 verify various aspects about\n> objects larger than 4GB, which Git does not currently handle correctly when\n> run on a platform where size_t is 64-bit and unsigned long is 32-bit.\n>\n> Changes vs v1:\n>\n>  * Rebased onto master, which merged ps/odb-source-loose (with which these\n>    patches previously conflicted rather badly).\n\nVery much appreciated.  There was a rather old set of patches by\nPhilip Oakley you relayed earlier, which had the same issue, by the\nway.  Will queue, and will try to take a look if I can find time\nbefore -rc1 but no promises X-<.\n\n"},{"id":"545690","messageId":"xmqqwlvy18js.fsf@gitster.g","threadId":"65750","inReplyTo":"66a642c39e7755755fe388af7612ac8c9bf41a5a.1781524349.git.gitgitgadget@gmail.com","subject":"Re: [PATCH v2 2/7] patch-delta: use size_t for sizes","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2026-06-16T21:26:15Z","receivedAt":"2026-06-16T21:26:18Z","isPatch":true,"body":"\"Johannes Schindelin via GitGitGadget\" <gitgitgadget@gmail.com>\nwrites:\n\n> Widen `patch_delta()`'s three size parameters to `size_t` and switch\n> its internal use of `get_delta_hdr_size()` to the `_sz` variant.\n> Then propagate the wider type through the callers.\n\nMakes sense.  \n"},{"id":"545836","messageId":"ajPhBn7n1wR-sii4@pks.im","threadId":"65750","inReplyTo":"pull.2137.v2.git.1781524349.gitgitgadget@gmail.com","subject":"Re: [PATCH v2 0/7] More work supporting objects larger than 4GB on Windows","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2026-06-18T12:13:58Z","receivedAt":"2026-06-18T12:14:05Z","isPatch":true,"body":"On Mon, Jun 15, 2026 at 11:52:22AM +0000, Johannes Schindelin via GitGitGadget wrote:\n> This patch series tries to address the problems pointed out by the expensive\n> tests that now run in CI: t5608 and t7508 verify various aspects about\n> objects larger than 4GB, which Git does not currently handle correctly when\n> run on a platform where size_t is 64-bit and unsigned long is 32-bit.\n> \n> Changes vs v1:\n> \n>  * Rebased onto master, which merged ps/odb-source-loose (with which these\n>    patches previously conflicted rather badly).\n>  * Removed superfluous size_t s variables (thanks, Patrick!).\n\nI skimmed those parts that I was previously commenting on and am\nhappy with those changes. Thanks!\n\nPatrick\n"},{"id":"545857","messageId":"xmqqwlvvsx6i.fsf@gitster.g","threadId":"65750","inReplyTo":"ajPhBn7n1wR-sii4@pks.im","subject":"Re: [PATCH v2 0/7] More work supporting objects larger than 4GB on Windows","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2026-06-18T15:08:53Z","receivedAt":"2026-06-18T15:08:55Z","isPatch":true,"body":"Patrick Steinhardt <ps@pks.im> writes:\n\n> On Mon, Jun 15, 2026 at 11:52:22AM +0000, Johannes Schindelin via GitGitGadget wrote:\n>> This patch series tries to address the problems pointed out by the expensive\n>> tests that now run in CI: t5608 and t7508 verify various aspects about\n>> objects larger than 4GB, which Git does not currently handle correctly when\n>> run on a platform where size_t is 64-bit and unsigned long is 32-bit.\n>> \n>> Changes vs v1:\n>> \n>>  * Rebased onto master, which merged ps/odb-source-loose (with which these\n>>    patches previously conflicted rather badly).\n>>  * Removed superfluous size_t s variables (thanks, Patrick!).\n>\n> I skimmed those parts that I was previously commenting on and am\n> happy with those changes. Thanks!\n\nThanks.  I looked at them and found nothing iffy, either.\n"}]}