[PATCH 1/2] archive: use size_t for the size of archive entries
flat view
HOTtoday
From: Elia Pinto <hidden>
Date: 2026-11-01 09:19:29
Subsystem:
the rest · Maintainer:
Linus Torvalds
The archive entry callback and format implementations use "unsigned long" for the entry size, while blobs above core.bigFileThreshold arrive as size_t. On platforms where "long" is 32 bits but size_t is 64 bits, such as 64-bit Windows, streaming a file of 4GiB or more causes silent corruption: for tar, the truncated size goes into the ustar header while stream_blocked() writes the entire blob, corrupting the archive; for zip, write_zip_entry() overflows compressed_size, producing incorrect headers and a corrupted archive. This was verified using a 16-bit simulation, where tar extracted truncated data and Python's zipfile rejected the output due to bad magic numbers or CRC-32 errors. Use size_t in the callback, tar writer, and zip writer functions, allowing the existing zip64 helpers to handle large files correctly. Triggering this requires processing a file of 4GiB or more on a platform where "long" is 32 bits but size_t is 64 bits, so no test is added. Signed-off-by: Elia Pinto <redacted> --- archive-tar.c | 10 +++++----- archive-zip.c | 16 ++++++++-------- archive.h | 2 +- 3 files changed, 14 insertions(+), 14 deletions(-)
diff --git a/archive-tar.c b/archive-tar.c
index a1c66024d4..31ab704886 100644
--- a/archive-tar.c
+++ b/archive-tar.c@@ -66,7 +66,7 @@ static void write_if_needed(void) * queues up writes, so that all our write(2) calls write exactly one * full block; pads writes to RECORDSIZE */ -static void do_write_blocked(const void *data, unsigned long size) +static void do_write_blocked(const void *data, size_t size) { const char *buf = data;
@@ -102,7 +102,7 @@ static void finish_record(void) write_if_needed(); } -static void write_blocked(const void *data, unsigned long size) +static void write_blocked(const void *data, size_t size) { do_write_blocked(data, size); finish_record();
@@ -218,7 +218,7 @@ static size_t get_path_prefix(const char *path, size_t pathlen, size_t maxlen) static void prepare_header(struct archiver_args *args, struct ustar_header *header, - unsigned int mode, unsigned long size) + unsigned int mode, size_t size) { xsnprintf(header->mode, sizeof(header->mode), "%07o", mode & 07777); xsnprintf(header->size, sizeof(header->size), "%011"PRIoMAX , S_ISREG(mode) ? (uintmax_t)size : (uintmax_t)0);
@@ -256,11 +256,11 @@ static int write_tar_entry(struct archiver_args *args, const struct object_id *oid, const char *path, size_t pathlen, unsigned int mode, - void *buffer, unsigned long size) + void *buffer, size_t size) { struct ustar_header header; struct strbuf ext_header = STRBUF_INIT; - unsigned long size_in_header; + size_t size_in_header; int err = 0; memset(&header, 0, sizeof(header));
diff --git a/archive-zip.c b/archive-zip.c
index 785689584c..2ca6dd956d 100644
--- a/archive-zip.c
+++ b/archive-zip.c@@ -191,9 +191,9 @@ static uint32_t clamp32(uintmax_t n) return (n < max) ? n : max; } -static void *zlib_deflate_raw(void *data, unsigned long size, +static void *zlib_deflate_raw(void *data, size_t size, int compression_level, - unsigned long *compressed_size) + size_t *compressed_size) { git_zstream stream; size_t maxsize;
@@ -224,8 +224,8 @@ static void *zlib_deflate_raw(void *data, unsigned long size, return buffer; } -static void write_zip_data_desc(unsigned long size, - unsigned long compressed_size, +static void write_zip_data_desc(size_t size, + size_t compressed_size, unsigned long crc) { if (size >= 0xffffffff || compressed_size >= 0xffffffff) {
@@ -248,8 +248,8 @@ static void write_zip_data_desc(unsigned long size, } static void set_zip_header_data_desc(struct zip_local_header *header, - unsigned long size, - unsigned long compressed_size, + size_t size, + size_t compressed_size, unsigned long crc) { copy_le32(header->crc32, crc);
@@ -285,7 +285,7 @@ static int write_zip_entry(struct archiver_args *args, const struct object_id *oid, const char *path, size_t pathlen, unsigned int mode, - void *buffer, unsigned long size) + void *buffer, size_t size) { struct zip_local_header header; uintmax_t offset = zip_offset;
@@ -293,7 +293,7 @@ static int write_zip_entry(struct archiver_args *args, size_t header_extra_size = zip_extra_mtime.len; int need_zip64_extra = 0; unsigned long attr2; - unsigned long compressed_size; + size_t compressed_size; unsigned long crc; enum zip_method method; unsigned char *out;
diff --git a/archive.h b/archive.h
index bbe65ba0f9..e52328d639 100644
--- a/archive.h
+++ b/archive.h@@ -56,7 +56,7 @@ typedef int (*write_archive_entry_fn_t)(struct archiver_args *args, const struct object_id *oid, const char *path, size_t pathlen, unsigned int mode, - void *buffer, unsigned long size); + void *buffer, size_t size); int write_archive_entries(struct archiver_args *args, write_archive_entry_fn_t write_entry);
--
2.53.0