mirror of
https://github.com/git-for-windows/git.git
synced 2026-06-20 23:54:45 -05:00
The odb_read_stream structure uses unsigned long for the size field,
which is 32-bit on Windows even in 64-bit builds. When streaming
objects larger than 4GB, the size would be truncated to zero or an
incorrect value, resulting in empty files being written to disk.
Change the size field in odb_read_stream to size_t and introduce
unpack_object_header_sz() to return sizes via size_t pointer. Since
object_info.sizep remains unsigned long for API compatibility, use
temporary variables where the types differ, with comments noting the
truncation limitation for code paths that still use unsigned long.
Widening the producers to size_t in this way introduces a handful of
silent size_t -> unsigned long narrowings on Windows, all in
builtin/pack-objects.c, where the consumers are still typed
unsigned long. Make those narrowings explicit with
cast_size_t_to_ulong() so they assert loudly the moment an object
actually exceeds ULONG_MAX bytes:
- oe_get_size_slow() returns unsigned long but holds a size_t
locally; cast at the return.
- write_reuse_object() passes a size_t into check_pack_inflate(),
whose expect parameter is unsigned long; cast at the call.
- check_object() routes a size_t through SET_SIZE() and
SET_DELTA_SIZE(), both of which take unsigned long via
oe_set_size() / oe_set_delta_size(); cast at the three call
sites in the OBJ_OFS_DELTA / OBJ_REF_DELTA branches and in the
non-delta default arm.
The cast-only treatment is deliberately a stop-gap. Properly
widening oe_set_size, oe_get_size_slow's return type,
check_pack_inflate's expect parameter, object_info.sizep,
patch_delta, and the OE_SIZE_BITS bit-fields cascades into a series
that is too large to be reviewable, so the proper widening is
deferred to a follow-up topic. Until then,
cast_size_t_to_ulong() at least makes the truncation explicit at
the source: it documents the boundary, and on a 64-bit non-Windows
platform it is a no-op.
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.
Helped-by: Torsten Bögershausen <tboegi@web.de>
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
68 lines
2.1 KiB
C
68 lines
2.1 KiB
C
/*
|
|
* Copyright (c) 2011, Google Inc.
|
|
*/
|
|
#ifndef STREAMING_H
|
|
#define STREAMING_H 1
|
|
|
|
#include "object.h"
|
|
|
|
struct object_database;
|
|
struct odb_read_stream;
|
|
struct stream_filter;
|
|
|
|
typedef int (*odb_read_stream_close_fn)(struct odb_read_stream *);
|
|
typedef ssize_t (*odb_read_stream_read_fn)(struct odb_read_stream *, char *, size_t);
|
|
|
|
/*
|
|
* A stream that can be used to read an object from the object database without
|
|
* loading all of it into memory.
|
|
*/
|
|
struct odb_read_stream {
|
|
odb_read_stream_close_fn close;
|
|
odb_read_stream_read_fn read;
|
|
enum object_type type;
|
|
size_t size; /* inflated size of full object */
|
|
};
|
|
|
|
/*
|
|
* Create a new object stream for the given object database. An optional filter
|
|
* can be used to transform the object's content.
|
|
*
|
|
* Returns the stream on success, a `NULL` pointer otherwise.
|
|
*/
|
|
struct odb_read_stream *odb_read_stream_open(struct object_database *odb,
|
|
const struct object_id *oid,
|
|
struct stream_filter *filter);
|
|
|
|
/*
|
|
* Close the given read stream and release all resources associated with it.
|
|
* Returns 0 on success, a negative error code otherwise.
|
|
*/
|
|
int odb_read_stream_close(struct odb_read_stream *stream);
|
|
|
|
/*
|
|
* Read data from the stream into the buffer. Returns 0 on EOF and the number
|
|
* of bytes read on success. Returns a negative error code in case reading from
|
|
* the stream fails.
|
|
*/
|
|
ssize_t odb_read_stream_read(struct odb_read_stream *stream, void *buf, size_t len);
|
|
|
|
/*
|
|
* Look up the object by its ID and write the full contents to the file
|
|
* descriptor. The object must be a blob, or the function will fail. When
|
|
* provided, the filter is used to transform the blob contents.
|
|
*
|
|
* `can_seek` should be set to 1 in case the given file descriptor can be
|
|
* seek(3p)'d on. This is used to support files with holes in case a
|
|
* significant portion of the blob contains NUL bytes.
|
|
*
|
|
* Returns a negative error code on failure, 0 on success.
|
|
*/
|
|
int odb_stream_blob_to_fd(struct object_database *odb,
|
|
int fd,
|
|
const struct object_id *oid,
|
|
struct stream_filter *filter,
|
|
int can_seek);
|
|
|
|
#endif /* STREAMING_H */
|