Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit adedac5

Browse files
author
Edward Thomson
committed
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.
1 parent f4e3dae commit adedac5

File tree

7 files changed

+80
-19
lines changed

7 files changed

+80
-19
lines changed

include/git2/diff.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -490,6 +490,14 @@ typedef struct {
490490

491491
/** Structure describing the binary contents of a diff. */
492492
typedef struct {
493+
/**
494+
* Whether there is data in this binary structure or not. If this
495+
* is `1`, then this was produced and included binary content. If
496+
* this is `0` then this was generated knowing only that a binary
497+
* file changed but without providing the data, probably from a patch
498+
* that said `Binary files a/file.txt and b/file.txt differ`.
499+
*/
500+
unsigned int contains_data;
493501
git_diff_binary_file old_file; /**< The contents of the old file. */
494502
git_diff_binary_file new_file; /**< The contents of the new file. */
495503
} git_diff_binary;

src/apply.c

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -291,7 +291,15 @@ static int apply_binary(
291291
git_patch *patch)
292292
{
293293
git_buf reverse = GIT_BUF_INIT;
294-
int error;
294+
int error = 0;
295+
296+
if (!patch->binary.contains_data) {
297+
error = apply_err("patch does not contain binary data");
298+
goto done;
299+
}
300+
301+
if (!patch->binary.old_file.datalen && !patch->binary.new_file.datalen)
302+
goto done;
295303

296304
/* first, apply the new_file delta to the given source */
297305
if ((error = apply_binary_delta(out, source, source_len,

src/diff_print.c

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -500,7 +500,6 @@ static int diff_print_patch_file_binary_noshow(
500500
&new_path, new_pfx, delta->new_file.path)) < 0)
501501
goto done;
502502

503-
504503
pi->line.num_lines = 1;
505504
error = diff_delta_format_with_paths(
506505
pi->buf, delta, "Binary files %s and %s differ\n",
@@ -524,7 +523,7 @@ static int diff_print_patch_file_binary(
524523
if (delta->status == GIT_DELTA_UNMODIFIED)
525524
return 0;
526525

527-
if ((pi->flags & GIT_DIFF_SHOW_BINARY) == 0)
526+
if ((pi->flags & GIT_DIFF_SHOW_BINARY) == 0 || !binary->contains_data)
528527
return diff_print_patch_file_binary_noshow(
529528
pi, delta, old_pfx, new_pfx);
530529

@@ -563,8 +562,11 @@ static int diff_print_patch_file(
563562
bool binary = (delta->flags & GIT_DIFF_FLAG_BINARY) ||
564563
(pi->flags & GIT_DIFF_FORCE_BINARY);
565564
bool show_binary = !!(pi->flags & GIT_DIFF_SHOW_BINARY);
566-
int id_strlen = binary && show_binary ?
567-
GIT_OID_HEXSZ : pi->id_strlen;
565+
int id_strlen = pi->id_strlen;
566+
567+
if (binary && show_binary)
568+
id_strlen = delta->old_file.id_abbrev ? delta->old_file.id_abbrev :
569+
delta->new_file.id_abbrev;
568570

569571
GIT_UNUSED(progress);
570572

src/patch_generate.c

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -342,7 +342,7 @@ static int create_binary(
342342

343343
static int diff_binary(git_patch_generated_output *output, git_patch_generated *patch)
344344
{
345-
git_diff_binary binary = {{0}};
345+
git_diff_binary binary = {0};
346346
const char *old_data = patch->ofile.map.data;
347347
const char *new_data = patch->nfile.map.data;
348348
size_t old_len = patch->ofile.map.len,
@@ -352,6 +352,8 @@ static int diff_binary(git_patch_generated_output *output, git_patch_generated *
352352
/* Only load contents if the user actually wants to diff
353353
* binary files. */
354354
if (patch->base.diff_opts.flags & GIT_DIFF_SHOW_BINARY) {
355+
binary.contains_data = 1;
356+
355357
/* Create the old->new delta (as the "new" side of the patch),
356358
* and the new->old delta (as the "old" side)
357359
*/
@@ -492,8 +494,17 @@ static int diff_single_generate(patch_generated_with_delta *pd, git_xdiff_output
492494
patch_generated_init_common(patch);
493495

494496
if (pd->delta.status == GIT_DELTA_UNMODIFIED &&
495-
!(patch->ofile.opts_flags & GIT_DIFF_INCLUDE_UNMODIFIED))
497+
!(patch->ofile.opts_flags & GIT_DIFF_INCLUDE_UNMODIFIED)) {
498+
499+
/* Even empty patches are flagged as binary, and even though
500+
* there's no difference, we flag this as "containing data"
501+
* (the data is known to be empty, as opposed to wholly unknown).
502+
*/
503+
if (patch->base.diff_opts.flags & GIT_DIFF_SHOW_BINARY)
504+
patch->base.binary.contains_data = 1;
505+
496506
return error;
507+
}
497508

498509
error = patch_generated_invoke_file_callback(patch, (git_patch_generated_output *)xo);
499510

src/patch_parse.c

Lines changed: 33 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -74,8 +74,8 @@ static int parse_advance_expected(
7474
return 0;
7575
}
7676

77-
#define parse_advance_expected_s(ctx, str) \
78-
parse_advance_expected(ctx, str, sizeof(str) - 1)
77+
#define parse_advance_expected_str(ctx, str) \
78+
parse_advance_expected(ctx, str, strlen(str))
7979

8080
static int parse_advance_ws(git_patch_parse_ctx *ctx)
8181
{
@@ -220,7 +220,7 @@ static int parse_header_git_index(
220220
{
221221
if (parse_header_oid(&patch->base.delta->old_file.id,
222222
&patch->base.delta->old_file.id_abbrev, ctx) < 0 ||
223-
parse_advance_expected_s(ctx, "..") < 0 ||
223+
parse_advance_expected_str(ctx, "..") < 0 ||
224224
parse_header_oid(&patch->base.delta->new_file.id,
225225
&patch->base.delta->new_file.id_abbrev, ctx) < 0)
226226
return -1;
@@ -336,7 +336,7 @@ static int parse_header_percent(uint16_t *out, git_patch_parse_ctx *ctx)
336336

337337
parse_advance_chars(ctx, (end - ctx->line));
338338

339-
if (parse_advance_expected_s(ctx, "%") < 0)
339+
if (parse_advance_expected_str(ctx, "%") < 0)
340340
return -1;
341341

342342
if (val > 100)
@@ -379,6 +379,7 @@ static const header_git_op header_git_ops[] = {
379379
{ "diff --git ", NULL },
380380
{ "@@ -", NULL },
381381
{ "GIT binary patch", NULL },
382+
{ "Binary files ", NULL },
382383
{ "--- ", parse_header_git_oldpath },
383384
{ "+++ ", parse_header_git_newpath },
384385
{ "index ", parse_header_git_index },
@@ -404,7 +405,7 @@ static int parse_header_git(
404405
int error = 0;
405406

406407
/* Parse the diff --git line */
407-
if (parse_advance_expected_s(ctx, "diff --git ") < 0)
408+
if (parse_advance_expected_str(ctx, "diff --git ") < 0)
408409
return parse_err("corrupt git diff header at line %d", ctx->line_num);
409410

410411
if (parse_header_path(&patch->header_old_path, ctx) < 0)
@@ -443,7 +444,7 @@ static int parse_header_git(
443444
goto done;
444445

445446
parse_advance_ws(ctx);
446-
parse_advance_expected_s(ctx, "\n");
447+
parse_advance_expected_str(ctx, "\n");
447448

448449
if (ctx->line_len > 0) {
449450
error = parse_err("trailing data at line %d", ctx->line_num);
@@ -505,27 +506,27 @@ static int parse_hunk_header(
505506
hunk->hunk.old_lines = 1;
506507
hunk->hunk.new_lines = 1;
507508

508-
if (parse_advance_expected_s(ctx, "@@ -") < 0 ||
509+
if (parse_advance_expected_str(ctx, "@@ -") < 0 ||
509510
parse_int(&hunk->hunk.old_start, ctx) < 0)
510511
goto fail;
511512

512513
if (ctx->line_len > 0 && ctx->line[0] == ',') {
513-
if (parse_advance_expected_s(ctx, ",") < 0 ||
514+
if (parse_advance_expected_str(ctx, ",") < 0 ||
514515
parse_int(&hunk->hunk.old_lines, ctx) < 0)
515516
goto fail;
516517
}
517518

518-
if (parse_advance_expected_s(ctx, " +") < 0 ||
519+
if (parse_advance_expected_str(ctx, " +") < 0 ||
519520
parse_int(&hunk->hunk.new_start, ctx) < 0)
520521
goto fail;
521522

522523
if (ctx->line_len > 0 && ctx->line[0] == ',') {
523-
if (parse_advance_expected_s(ctx, ",") < 0 ||
524+
if (parse_advance_expected_str(ctx, ",") < 0 ||
524525
parse_int(&hunk->hunk.new_lines, ctx) < 0)
525526
goto fail;
526527
}
527528

528-
if (parse_advance_expected_s(ctx, " @@") < 0)
529+
if (parse_advance_expected_str(ctx, " @@") < 0)
529530
goto fail;
530531

531532
parse_advance_line(ctx);
@@ -782,7 +783,7 @@ static int parse_patch_binary(
782783
{
783784
int error;
784785

785-
if (parse_advance_expected_s(ctx, "GIT binary patch") < 0 ||
786+
if (parse_advance_expected_str(ctx, "GIT binary patch") < 0 ||
786787
parse_advance_nl(ctx) < 0)
787788
return parse_err("corrupt git binary header at line %d", ctx->line_num);
788789

@@ -804,6 +805,24 @@ static int parse_patch_binary(
804805
return parse_err("corrupt git binary patch separator at line %d",
805806
ctx->line_num);
806807

808+
patch->base.binary.contains_data = 1;
809+
patch->base.delta->flags |= GIT_DIFF_FLAG_BINARY;
810+
return 0;
811+
}
812+
813+
static int parse_patch_binary_nodata(
814+
git_patch_parsed *patch,
815+
git_patch_parse_ctx *ctx)
816+
{
817+
if (parse_advance_expected_str(ctx, "Binary files ") < 0 ||
818+
parse_advance_expected_str(ctx, patch->header_old_path) < 0 ||
819+
parse_advance_expected_str(ctx, " and ") < 0 ||
820+
parse_advance_expected_str(ctx, patch->header_new_path) < 0 ||
821+
parse_advance_expected_str(ctx, " differ") < 0 ||
822+
parse_advance_nl(ctx) < 0)
823+
return parse_err("corrupt git binary header at line %d", ctx->line_num);
824+
825+
patch->base.binary.contains_data = 0;
807826
patch->base.delta->flags |= GIT_DIFF_FLAG_BINARY;
808827
return 0;
809828
}
@@ -840,6 +859,8 @@ static int parse_patch_body(
840859
{
841860
if (parse_ctx_contains_s(ctx, "GIT binary patch"))
842861
return parse_patch_binary(patch, ctx);
862+
else if (parse_ctx_contains_s(ctx, "Binary files "))
863+
return parse_patch_binary_nodata(patch, ctx);
843864
else
844865
return parse_patch_hunks(patch, ctx);
845866
}

tests/patch/patch_common.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -661,3 +661,8 @@
661661
"\n" \
662662
"delta 48\n" \
663663
"mc$~Y)c#%<%fq{_;hPgsAGK(h)CJASj=y9P)1m{m|^9BI99|yz$\n\n"
664+
665+
#define PATCH_BINARY_NOT_PRINTED \
666+
"diff --git a/binary.bin b/binary.bin\n" \
667+
"index 27184d9..7c94f9e 100644\n" \
668+
"Binary files a/binary.bin and b/binary.bin differ\n"

tests/patch/print.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,3 +166,9 @@ void test_patch_print__not_reversible(void)
166166
patch_print_from_patchfile(PATCH_BINARY_NOT_REVERSIBLE,
167167
strlen(PATCH_BINARY_NOT_REVERSIBLE));
168168
}
169+
170+
void test_patch_print__binary_not_shown(void)
171+
{
172+
patch_print_from_patchfile(PATCH_BINARY_NOT_PRINTED,
173+
strlen(PATCH_BINARY_NOT_PRINTED));
174+
}

0 commit comments

Comments
 (0)