delta, packfile: use size_t for delta header sizes
The delta header decoding functions return unsigned long, which truncates on Windows for objects larger than 4GB. Introduce size_t variants get_delta_hdr_size_sz() and get_size_from_delta_sz() that preserve the full 64-bit size, and use them in packed_object_info() where the size is needed for streaming decisions. This was originally authored by LordKiRon <https://github.com/LordKiRon>, who preferred not to reveal their real name and therefore agreed that I take over authorship. Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>main
parent
606c192380
commit
17fa077596
14
delta.h
14
delta.h
|
|
@ -86,8 +86,11 @@ void *patch_delta(const void *src_buf, unsigned long src_size,
|
|||
* This must be called twice on the delta data buffer, first to get the
|
||||
* expected source buffer size, and again to get the target buffer size.
|
||||
*/
|
||||
static inline unsigned long get_delta_hdr_size(const unsigned char **datap,
|
||||
const unsigned char *top)
|
||||
/*
|
||||
* Size_t variant that doesn't truncate - use for >4GB objects on Windows.
|
||||
*/
|
||||
static inline size_t get_delta_hdr_size_sz(const unsigned char **datap,
|
||||
const unsigned char *top)
|
||||
{
|
||||
const unsigned char *data = *datap;
|
||||
size_t cmd, size = 0;
|
||||
|
|
@ -98,6 +101,13 @@ static inline unsigned long get_delta_hdr_size(const unsigned char **datap,
|
|||
i += 7;
|
||||
} while (cmd & 0x80 && data < top);
|
||||
*datap = data;
|
||||
return size;
|
||||
}
|
||||
|
||||
static inline unsigned long get_delta_hdr_size(const unsigned char **datap,
|
||||
const unsigned char *top)
|
||||
{
|
||||
size_t size = get_delta_hdr_size_sz(datap, top);
|
||||
return cast_size_t_to_ulong(size);
|
||||
}
|
||||
|
||||
|
|
|
|||
33
packfile.c
33
packfile.c
|
|
@ -1161,9 +1161,12 @@ unsigned long unpack_object_header_buffer(const unsigned char *buf,
|
|||
return used;
|
||||
}
|
||||
|
||||
unsigned long get_size_from_delta(struct packed_git *p,
|
||||
struct pack_window **w_curs,
|
||||
off_t curpos)
|
||||
/*
|
||||
* Size_t variant for >4GB delta results on Windows.
|
||||
*/
|
||||
static size_t get_size_from_delta_sz(struct packed_git *p,
|
||||
struct pack_window **w_curs,
|
||||
off_t curpos)
|
||||
{
|
||||
const unsigned char *data;
|
||||
unsigned char delta_head[20], *in;
|
||||
|
|
@ -1210,10 +1213,18 @@ unsigned long get_size_from_delta(struct packed_git *p,
|
|||
data = delta_head;
|
||||
|
||||
/* ignore base size */
|
||||
get_delta_hdr_size(&data, delta_head+sizeof(delta_head));
|
||||
get_delta_hdr_size_sz(&data, delta_head+sizeof(delta_head));
|
||||
|
||||
/* Read the result size */
|
||||
return get_delta_hdr_size(&data, delta_head+sizeof(delta_head));
|
||||
return get_delta_hdr_size_sz(&data, delta_head+sizeof(delta_head));
|
||||
}
|
||||
|
||||
unsigned long get_size_from_delta(struct packed_git *p,
|
||||
struct pack_window **w_curs,
|
||||
off_t curpos)
|
||||
{
|
||||
size_t size = get_size_from_delta_sz(p, w_curs, curpos);
|
||||
return cast_size_t_to_ulong(size);
|
||||
}
|
||||
|
||||
int unpack_object_header(struct packed_git *p,
|
||||
|
|
@ -1618,14 +1629,18 @@ static int packed_object_info_with_index_pos(struct packed_git *p, off_t obj_off
|
|||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
*oi->sizep = get_size_from_delta(p, &w_curs, tmp_pos);
|
||||
if (*oi->sizep == 0) {
|
||||
/*
|
||||
* Use size_t variant to avoid die() on >4GB deltas.
|
||||
* oi->sizep is unsigned long, so truncation may occur,
|
||||
* but streaming code uses its own size_t tracking.
|
||||
*/
|
||||
size = get_size_from_delta_sz(p, &w_curs, tmp_pos);
|
||||
if (size == 0) {
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
} else {
|
||||
*oi->sizep = size;
|
||||
}
|
||||
*oi->sizep = (unsigned long)size;
|
||||
}
|
||||
|
||||
if (oi->disk_sizep || (oi->mtimep && p->is_cruft)) {
|
||||
|
|
|
|||
Loading…
Reference in New Issue