mirror of
https://git.proxmox.com/git/libgit2
synced 2025-05-04 11:52:09 +00:00
diff: treat binary patches with no data special
When creating and printing diffs, deal with binary deltas that have binary data specially, versus diffs that have a binary file but lack the actual binary data.
This commit is contained in:
parent
f4e3dae75f
commit
adedac5aba
@ -490,6 +490,14 @@ typedef struct {
|
|||||||
|
|
||||||
/** Structure describing the binary contents of a diff. */
|
/** Structure describing the binary contents of a diff. */
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
/**
|
||||||
|
* Whether there is data in this binary structure or not. If this
|
||||||
|
* is `1`, then this was produced and included binary content. If
|
||||||
|
* this is `0` then this was generated knowing only that a binary
|
||||||
|
* file changed but without providing the data, probably from a patch
|
||||||
|
* that said `Binary files a/file.txt and b/file.txt differ`.
|
||||||
|
*/
|
||||||
|
unsigned int contains_data;
|
||||||
git_diff_binary_file old_file; /**< The contents of the old file. */
|
git_diff_binary_file old_file; /**< The contents of the old file. */
|
||||||
git_diff_binary_file new_file; /**< The contents of the new file. */
|
git_diff_binary_file new_file; /**< The contents of the new file. */
|
||||||
} git_diff_binary;
|
} git_diff_binary;
|
||||||
|
10
src/apply.c
10
src/apply.c
@ -291,7 +291,15 @@ static int apply_binary(
|
|||||||
git_patch *patch)
|
git_patch *patch)
|
||||||
{
|
{
|
||||||
git_buf reverse = GIT_BUF_INIT;
|
git_buf reverse = GIT_BUF_INIT;
|
||||||
int error;
|
int error = 0;
|
||||||
|
|
||||||
|
if (!patch->binary.contains_data) {
|
||||||
|
error = apply_err("patch does not contain binary data");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!patch->binary.old_file.datalen && !patch->binary.new_file.datalen)
|
||||||
|
goto done;
|
||||||
|
|
||||||
/* first, apply the new_file delta to the given source */
|
/* first, apply the new_file delta to the given source */
|
||||||
if ((error = apply_binary_delta(out, source, source_len,
|
if ((error = apply_binary_delta(out, source, source_len,
|
||||||
|
@ -500,7 +500,6 @@ static int diff_print_patch_file_binary_noshow(
|
|||||||
&new_path, new_pfx, delta->new_file.path)) < 0)
|
&new_path, new_pfx, delta->new_file.path)) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
|
|
||||||
pi->line.num_lines = 1;
|
pi->line.num_lines = 1;
|
||||||
error = diff_delta_format_with_paths(
|
error = diff_delta_format_with_paths(
|
||||||
pi->buf, delta, "Binary files %s and %s differ\n",
|
pi->buf, delta, "Binary files %s and %s differ\n",
|
||||||
@ -524,7 +523,7 @@ static int diff_print_patch_file_binary(
|
|||||||
if (delta->status == GIT_DELTA_UNMODIFIED)
|
if (delta->status == GIT_DELTA_UNMODIFIED)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if ((pi->flags & GIT_DIFF_SHOW_BINARY) == 0)
|
if ((pi->flags & GIT_DIFF_SHOW_BINARY) == 0 || !binary->contains_data)
|
||||||
return diff_print_patch_file_binary_noshow(
|
return diff_print_patch_file_binary_noshow(
|
||||||
pi, delta, old_pfx, new_pfx);
|
pi, delta, old_pfx, new_pfx);
|
||||||
|
|
||||||
@ -563,8 +562,11 @@ static int diff_print_patch_file(
|
|||||||
bool binary = (delta->flags & GIT_DIFF_FLAG_BINARY) ||
|
bool binary = (delta->flags & GIT_DIFF_FLAG_BINARY) ||
|
||||||
(pi->flags & GIT_DIFF_FORCE_BINARY);
|
(pi->flags & GIT_DIFF_FORCE_BINARY);
|
||||||
bool show_binary = !!(pi->flags & GIT_DIFF_SHOW_BINARY);
|
bool show_binary = !!(pi->flags & GIT_DIFF_SHOW_BINARY);
|
||||||
int id_strlen = binary && show_binary ?
|
int id_strlen = pi->id_strlen;
|
||||||
GIT_OID_HEXSZ : pi->id_strlen;
|
|
||||||
|
if (binary && show_binary)
|
||||||
|
id_strlen = delta->old_file.id_abbrev ? delta->old_file.id_abbrev :
|
||||||
|
delta->new_file.id_abbrev;
|
||||||
|
|
||||||
GIT_UNUSED(progress);
|
GIT_UNUSED(progress);
|
||||||
|
|
||||||
|
@ -342,7 +342,7 @@ done:
|
|||||||
|
|
||||||
static int diff_binary(git_patch_generated_output *output, git_patch_generated *patch)
|
static int diff_binary(git_patch_generated_output *output, git_patch_generated *patch)
|
||||||
{
|
{
|
||||||
git_diff_binary binary = {{0}};
|
git_diff_binary binary = {0};
|
||||||
const char *old_data = patch->ofile.map.data;
|
const char *old_data = patch->ofile.map.data;
|
||||||
const char *new_data = patch->nfile.map.data;
|
const char *new_data = patch->nfile.map.data;
|
||||||
size_t old_len = patch->ofile.map.len,
|
size_t old_len = patch->ofile.map.len,
|
||||||
@ -352,6 +352,8 @@ static int diff_binary(git_patch_generated_output *output, git_patch_generated *
|
|||||||
/* Only load contents if the user actually wants to diff
|
/* Only load contents if the user actually wants to diff
|
||||||
* binary files. */
|
* binary files. */
|
||||||
if (patch->base.diff_opts.flags & GIT_DIFF_SHOW_BINARY) {
|
if (patch->base.diff_opts.flags & GIT_DIFF_SHOW_BINARY) {
|
||||||
|
binary.contains_data = 1;
|
||||||
|
|
||||||
/* Create the old->new delta (as the "new" side of the patch),
|
/* Create the old->new delta (as the "new" side of the patch),
|
||||||
* and the new->old delta (as the "old" side)
|
* and the new->old delta (as the "old" side)
|
||||||
*/
|
*/
|
||||||
@ -492,8 +494,17 @@ static int diff_single_generate(patch_generated_with_delta *pd, git_xdiff_output
|
|||||||
patch_generated_init_common(patch);
|
patch_generated_init_common(patch);
|
||||||
|
|
||||||
if (pd->delta.status == GIT_DELTA_UNMODIFIED &&
|
if (pd->delta.status == GIT_DELTA_UNMODIFIED &&
|
||||||
!(patch->ofile.opts_flags & GIT_DIFF_INCLUDE_UNMODIFIED))
|
!(patch->ofile.opts_flags & GIT_DIFF_INCLUDE_UNMODIFIED)) {
|
||||||
|
|
||||||
|
/* Even empty patches are flagged as binary, and even though
|
||||||
|
* there's no difference, we flag this as "containing data"
|
||||||
|
* (the data is known to be empty, as opposed to wholly unknown).
|
||||||
|
*/
|
||||||
|
if (patch->base.diff_opts.flags & GIT_DIFF_SHOW_BINARY)
|
||||||
|
patch->base.binary.contains_data = 1;
|
||||||
|
|
||||||
return error;
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
error = patch_generated_invoke_file_callback(patch, (git_patch_generated_output *)xo);
|
error = patch_generated_invoke_file_callback(patch, (git_patch_generated_output *)xo);
|
||||||
|
|
||||||
|
@ -74,8 +74,8 @@ static int parse_advance_expected(
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define parse_advance_expected_s(ctx, str) \
|
#define parse_advance_expected_str(ctx, str) \
|
||||||
parse_advance_expected(ctx, str, sizeof(str) - 1)
|
parse_advance_expected(ctx, str, strlen(str))
|
||||||
|
|
||||||
static int parse_advance_ws(git_patch_parse_ctx *ctx)
|
static int parse_advance_ws(git_patch_parse_ctx *ctx)
|
||||||
{
|
{
|
||||||
@ -220,7 +220,7 @@ static int parse_header_git_index(
|
|||||||
{
|
{
|
||||||
if (parse_header_oid(&patch->base.delta->old_file.id,
|
if (parse_header_oid(&patch->base.delta->old_file.id,
|
||||||
&patch->base.delta->old_file.id_abbrev, ctx) < 0 ||
|
&patch->base.delta->old_file.id_abbrev, ctx) < 0 ||
|
||||||
parse_advance_expected_s(ctx, "..") < 0 ||
|
parse_advance_expected_str(ctx, "..") < 0 ||
|
||||||
parse_header_oid(&patch->base.delta->new_file.id,
|
parse_header_oid(&patch->base.delta->new_file.id,
|
||||||
&patch->base.delta->new_file.id_abbrev, ctx) < 0)
|
&patch->base.delta->new_file.id_abbrev, ctx) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
@ -336,7 +336,7 @@ static int parse_header_percent(uint16_t *out, git_patch_parse_ctx *ctx)
|
|||||||
|
|
||||||
parse_advance_chars(ctx, (end - ctx->line));
|
parse_advance_chars(ctx, (end - ctx->line));
|
||||||
|
|
||||||
if (parse_advance_expected_s(ctx, "%") < 0)
|
if (parse_advance_expected_str(ctx, "%") < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
if (val > 100)
|
if (val > 100)
|
||||||
@ -379,6 +379,7 @@ static const header_git_op header_git_ops[] = {
|
|||||||
{ "diff --git ", NULL },
|
{ "diff --git ", NULL },
|
||||||
{ "@@ -", NULL },
|
{ "@@ -", NULL },
|
||||||
{ "GIT binary patch", NULL },
|
{ "GIT binary patch", NULL },
|
||||||
|
{ "Binary files ", NULL },
|
||||||
{ "--- ", parse_header_git_oldpath },
|
{ "--- ", parse_header_git_oldpath },
|
||||||
{ "+++ ", parse_header_git_newpath },
|
{ "+++ ", parse_header_git_newpath },
|
||||||
{ "index ", parse_header_git_index },
|
{ "index ", parse_header_git_index },
|
||||||
@ -404,7 +405,7 @@ static int parse_header_git(
|
|||||||
int error = 0;
|
int error = 0;
|
||||||
|
|
||||||
/* Parse the diff --git line */
|
/* Parse the diff --git line */
|
||||||
if (parse_advance_expected_s(ctx, "diff --git ") < 0)
|
if (parse_advance_expected_str(ctx, "diff --git ") < 0)
|
||||||
return parse_err("corrupt git diff header at line %d", ctx->line_num);
|
return parse_err("corrupt git diff header at line %d", ctx->line_num);
|
||||||
|
|
||||||
if (parse_header_path(&patch->header_old_path, ctx) < 0)
|
if (parse_header_path(&patch->header_old_path, ctx) < 0)
|
||||||
@ -443,7 +444,7 @@ static int parse_header_git(
|
|||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
parse_advance_ws(ctx);
|
parse_advance_ws(ctx);
|
||||||
parse_advance_expected_s(ctx, "\n");
|
parse_advance_expected_str(ctx, "\n");
|
||||||
|
|
||||||
if (ctx->line_len > 0) {
|
if (ctx->line_len > 0) {
|
||||||
error = parse_err("trailing data at line %d", ctx->line_num);
|
error = parse_err("trailing data at line %d", ctx->line_num);
|
||||||
@ -505,27 +506,27 @@ static int parse_hunk_header(
|
|||||||
hunk->hunk.old_lines = 1;
|
hunk->hunk.old_lines = 1;
|
||||||
hunk->hunk.new_lines = 1;
|
hunk->hunk.new_lines = 1;
|
||||||
|
|
||||||
if (parse_advance_expected_s(ctx, "@@ -") < 0 ||
|
if (parse_advance_expected_str(ctx, "@@ -") < 0 ||
|
||||||
parse_int(&hunk->hunk.old_start, ctx) < 0)
|
parse_int(&hunk->hunk.old_start, ctx) < 0)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
if (ctx->line_len > 0 && ctx->line[0] == ',') {
|
if (ctx->line_len > 0 && ctx->line[0] == ',') {
|
||||||
if (parse_advance_expected_s(ctx, ",") < 0 ||
|
if (parse_advance_expected_str(ctx, ",") < 0 ||
|
||||||
parse_int(&hunk->hunk.old_lines, ctx) < 0)
|
parse_int(&hunk->hunk.old_lines, ctx) < 0)
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (parse_advance_expected_s(ctx, " +") < 0 ||
|
if (parse_advance_expected_str(ctx, " +") < 0 ||
|
||||||
parse_int(&hunk->hunk.new_start, ctx) < 0)
|
parse_int(&hunk->hunk.new_start, ctx) < 0)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
if (ctx->line_len > 0 && ctx->line[0] == ',') {
|
if (ctx->line_len > 0 && ctx->line[0] == ',') {
|
||||||
if (parse_advance_expected_s(ctx, ",") < 0 ||
|
if (parse_advance_expected_str(ctx, ",") < 0 ||
|
||||||
parse_int(&hunk->hunk.new_lines, ctx) < 0)
|
parse_int(&hunk->hunk.new_lines, ctx) < 0)
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (parse_advance_expected_s(ctx, " @@") < 0)
|
if (parse_advance_expected_str(ctx, " @@") < 0)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
parse_advance_line(ctx);
|
parse_advance_line(ctx);
|
||||||
@ -782,7 +783,7 @@ static int parse_patch_binary(
|
|||||||
{
|
{
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
if (parse_advance_expected_s(ctx, "GIT binary patch") < 0 ||
|
if (parse_advance_expected_str(ctx, "GIT binary patch") < 0 ||
|
||||||
parse_advance_nl(ctx) < 0)
|
parse_advance_nl(ctx) < 0)
|
||||||
return parse_err("corrupt git binary header at line %d", ctx->line_num);
|
return parse_err("corrupt git binary header at line %d", ctx->line_num);
|
||||||
|
|
||||||
@ -804,6 +805,24 @@ static int parse_patch_binary(
|
|||||||
return parse_err("corrupt git binary patch separator at line %d",
|
return parse_err("corrupt git binary patch separator at line %d",
|
||||||
ctx->line_num);
|
ctx->line_num);
|
||||||
|
|
||||||
|
patch->base.binary.contains_data = 1;
|
||||||
|
patch->base.delta->flags |= GIT_DIFF_FLAG_BINARY;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int parse_patch_binary_nodata(
|
||||||
|
git_patch_parsed *patch,
|
||||||
|
git_patch_parse_ctx *ctx)
|
||||||
|
{
|
||||||
|
if (parse_advance_expected_str(ctx, "Binary files ") < 0 ||
|
||||||
|
parse_advance_expected_str(ctx, patch->header_old_path) < 0 ||
|
||||||
|
parse_advance_expected_str(ctx, " and ") < 0 ||
|
||||||
|
parse_advance_expected_str(ctx, patch->header_new_path) < 0 ||
|
||||||
|
parse_advance_expected_str(ctx, " differ") < 0 ||
|
||||||
|
parse_advance_nl(ctx) < 0)
|
||||||
|
return parse_err("corrupt git binary header at line %d", ctx->line_num);
|
||||||
|
|
||||||
|
patch->base.binary.contains_data = 0;
|
||||||
patch->base.delta->flags |= GIT_DIFF_FLAG_BINARY;
|
patch->base.delta->flags |= GIT_DIFF_FLAG_BINARY;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -840,6 +859,8 @@ static int parse_patch_body(
|
|||||||
{
|
{
|
||||||
if (parse_ctx_contains_s(ctx, "GIT binary patch"))
|
if (parse_ctx_contains_s(ctx, "GIT binary patch"))
|
||||||
return parse_patch_binary(patch, ctx);
|
return parse_patch_binary(patch, ctx);
|
||||||
|
else if (parse_ctx_contains_s(ctx, "Binary files "))
|
||||||
|
return parse_patch_binary_nodata(patch, ctx);
|
||||||
else
|
else
|
||||||
return parse_patch_hunks(patch, ctx);
|
return parse_patch_hunks(patch, ctx);
|
||||||
}
|
}
|
||||||
|
@ -661,3 +661,8 @@
|
|||||||
"\n" \
|
"\n" \
|
||||||
"delta 48\n" \
|
"delta 48\n" \
|
||||||
"mc$~Y)c#%<%fq{_;hPgsAGK(h)CJASj=y9P)1m{m|^9BI99|yz$\n\n"
|
"mc$~Y)c#%<%fq{_;hPgsAGK(h)CJASj=y9P)1m{m|^9BI99|yz$\n\n"
|
||||||
|
|
||||||
|
#define PATCH_BINARY_NOT_PRINTED \
|
||||||
|
"diff --git a/binary.bin b/binary.bin\n" \
|
||||||
|
"index 27184d9..7c94f9e 100644\n" \
|
||||||
|
"Binary files a/binary.bin and b/binary.bin differ\n"
|
||||||
|
@ -166,3 +166,9 @@ void test_patch_print__not_reversible(void)
|
|||||||
patch_print_from_patchfile(PATCH_BINARY_NOT_REVERSIBLE,
|
patch_print_from_patchfile(PATCH_BINARY_NOT_REVERSIBLE,
|
||||||
strlen(PATCH_BINARY_NOT_REVERSIBLE));
|
strlen(PATCH_BINARY_NOT_REVERSIBLE));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void test_patch_print__binary_not_shown(void)
|
||||||
|
{
|
||||||
|
patch_print_from_patchfile(PATCH_BINARY_NOT_PRINTED,
|
||||||
|
strlen(PATCH_BINARY_NOT_PRINTED));
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user