diff --git a/src/delta-apply.c b/src/delta-apply.c index 89745faa0..6e86a81db 100644 --- a/src/delta-apply.c +++ b/src/delta-apply.c @@ -49,6 +49,37 @@ int git__delta_read_header( return 0; } +#define DELTA_HEADER_BUFFER_LEN 16 +int git__delta_read_header_fromstream(size_t *base_sz, size_t *res_sz, git_packfile_stream *stream) +{ + static const size_t buffer_len = DELTA_HEADER_BUFFER_LEN; + unsigned char buffer[DELTA_HEADER_BUFFER_LEN]; + const unsigned char *delta, *delta_end; + size_t len; + ssize_t read; + + len = read = 0; + while (len < buffer_len) { + read = git_packfile_stream_read(stream, &buffer[len], buffer_len - len); + + if (read == 0) + break; + + if (read == GIT_EBUFS) + continue; + + len += read; + } + + delta = buffer; + delta_end = delta + len; + if ((hdr_sz(base_sz, &delta, delta_end) < 0) || + (hdr_sz(res_sz, &delta, delta_end) < 0)) + return -1; + + return 0; +} + int git__delta_apply( git_rawobj *out, const unsigned char *base, diff --git a/src/delta-apply.h b/src/delta-apply.h index d7d99d04c..eeeb78682 100644 --- a/src/delta-apply.h +++ b/src/delta-apply.h @@ -8,6 +8,7 @@ #define INCLUDE_delta_apply_h__ #include "odb.h" +#include "pack.h" /** * Apply a git binary delta to recover the original content. @@ -47,4 +48,15 @@ extern int git__delta_read_header( size_t *base_sz, size_t *res_sz); +/** + * Read the header of a git binary delta + * + * This variant reads just enough from the packfile stream to read the + * delta header. + */ +extern int git__delta_read_header_fromstream( + size_t *base_sz, + size_t *res_sz, + git_packfile_stream *stream); + #endif diff --git a/src/pack.c b/src/pack.c index e7003e66d..6a700e29f 100644 --- a/src/pack.c +++ b/src/pack.c @@ -499,15 +499,14 @@ int git_packfile_resolve_header( if (type == GIT_OBJ_OFS_DELTA || type == GIT_OBJ_REF_DELTA) { size_t base_size; - git_rawobj delta; + git_packfile_stream stream; + base_offset = get_delta_base(p, &w_curs, &curpos, type, offset); git_mwindow_close(&w_curs); - error = packfile_unpack_compressed(&delta, p, &w_curs, &curpos, size, type); - git_mwindow_close(&w_curs); - if (error < 0) + if ((error = git_packfile_stream_open(&stream, p, curpos)) < 0) return error; - error = git__delta_read_header(delta.data, delta.len, &base_size, size_p); - git__free(delta.data); + error = git__delta_read_header_fromstream(&base_size, size_p, &stream); + git_packfile_stream_free(&stream); if (error < 0) return error; } else