Skip to content

Commit 3cd4f5e

Browse files
author
Junio C Hamano
committed
git-apply --binary: clean up and prepare for --reverse
This cleans up the implementation of "git-apply --binary", and implements reverse application of binary patches (when git-diff is converted to emit reversible binary patches). Earlier, the types of encoding (either deflated literal or deflated delta) were stored in is_binary field in struct patch, which meant that we cannot store more than one fragment that differ in the encoding for a patch. This moves the information to a field in struct fragment that is otherwise unused for binary patches, and makes it possible to hang two (or more, but two is enough) hunks for a binary patch. The original "binary patch" output from git-diff is internally parsed into an "is_binary" patch with one fragment. Upcoming reversible binary patch output will have two fragments, the first one being the forward patch and the second one the reverse patch. Signed-off-by: Junio C Hamano <[email protected]>
1 parent d1b9944 commit 3cd4f5e

File tree

1 file changed

+141
-65
lines changed

1 file changed

+141
-65
lines changed

builtin-apply.c

Lines changed: 141 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,13 @@ static int max_change, max_len;
109109
*/
110110
static int linenr = 1;
111111

112+
/*
113+
* This represents one "hunk" from a patch, starting with
114+
* "@@ -oldpos,oldlines +newpos,newlines @@" marker. The
115+
* patch text is pointed at by patch, and its byte length
116+
* is stored in size. leading and trailing are the number
117+
* of context lines.
118+
*/
112119
struct fragment {
113120
unsigned long leading, trailing;
114121
unsigned long oldpos, oldlines;
@@ -118,12 +125,19 @@ struct fragment {
118125
struct fragment *next;
119126
};
120127

128+
/*
129+
* When dealing with a binary patch, we reuse "leading" field
130+
* to store the type of the binary hunk, either deflated "delta"
131+
* or deflated "literal".
132+
*/
133+
#define binary_patch_method leading
134+
#define BINARY_DELTA_DEFLATED 1
135+
#define BINARY_LITERAL_DEFLATED 2
136+
121137
struct patch {
122138
char *new_name, *old_name, *def_name;
123139
unsigned int old_mode, new_mode;
124140
int is_rename, is_copy, is_new, is_delete, is_binary;
125-
#define BINARY_DELTA_DEFLATED 1
126-
#define BINARY_LITERAL_DEFLATED 2
127141
unsigned long deflate_origlen;
128142
int lines_added, lines_deleted;
129143
int score;
@@ -979,43 +993,70 @@ static inline int metadata_changes(struct patch *patch)
979993
patch->old_mode != patch->new_mode);
980994
}
981995

982-
static int parse_binary(char *buffer, unsigned long size, struct patch *patch)
996+
static char *inflate_it(const void *data, unsigned long size,
997+
unsigned long inflated_size)
983998
{
984-
/* We have read "GIT binary patch\n"; what follows is a line
985-
* that says the patch method (currently, either "deflated
986-
* literal" or "deflated delta") and the length of data before
987-
* deflating; a sequence of 'length-byte' followed by base-85
988-
* encoded data follows.
999+
z_stream stream;
1000+
void *out;
1001+
int st;
1002+
1003+
memset(&stream, 0, sizeof(stream));
1004+
1005+
stream.next_in = (unsigned char *)data;
1006+
stream.avail_in = size;
1007+
stream.next_out = out = xmalloc(inflated_size);
1008+
stream.avail_out = inflated_size;
1009+
inflateInit(&stream);
1010+
st = inflate(&stream, Z_FINISH);
1011+
if ((st != Z_STREAM_END) || stream.total_out != inflated_size) {
1012+
free(out);
1013+
return NULL;
1014+
}
1015+
return out;
1016+
}
1017+
1018+
static struct fragment *parse_binary_hunk(char **buf_p,
1019+
unsigned long *sz_p,
1020+
int *status_p,
1021+
int *used_p)
1022+
{
1023+
/* Expect a line that begins with binary patch method ("literal"
1024+
* or "delta"), followed by the length of data before deflating.
1025+
* a sequence of 'length-byte' followed by base-85 encoded data
1026+
* should follow, terminated by a newline.
9891027
*
9901028
* Each 5-byte sequence of base-85 encodes up to 4 bytes,
9911029
* and we would limit the patch line to 66 characters,
9921030
* so one line can fit up to 13 groups that would decode
9931031
* to 52 bytes max. The length byte 'A'-'Z' corresponds
9941032
* to 1-26 bytes, and 'a'-'z' corresponds to 27-52 bytes.
995-
* The end of binary is signaled with an empty line.
9961033
*/
9971034
int llen, used;
998-
struct fragment *fragment;
1035+
unsigned long size = *sz_p;
1036+
char *buffer = *buf_p;
1037+
int patch_method;
1038+
unsigned long origlen;
9991039
char *data = NULL;
1040+
int hunk_size = 0;
1041+
struct fragment *frag;
10001042

1001-
patch->fragments = fragment = xcalloc(1, sizeof(*fragment));
1002-
1003-
/* Grab the type of patch */
10041043
llen = linelen(buffer, size);
10051044
used = llen;
1006-
linenr++;
1045+
1046+
*status_p = 0;
10071047

10081048
if (!strncmp(buffer, "delta ", 6)) {
1009-
patch->is_binary = BINARY_DELTA_DEFLATED;
1010-
patch->deflate_origlen = strtoul(buffer + 6, NULL, 10);
1049+
patch_method = BINARY_DELTA_DEFLATED;
1050+
origlen = strtoul(buffer + 6, NULL, 10);
10111051
}
10121052
else if (!strncmp(buffer, "literal ", 8)) {
1013-
patch->is_binary = BINARY_LITERAL_DEFLATED;
1014-
patch->deflate_origlen = strtoul(buffer + 8, NULL, 10);
1053+
patch_method = BINARY_LITERAL_DEFLATED;
1054+
origlen = strtoul(buffer + 8, NULL, 10);
10151055
}
10161056
else
1017-
return error("unrecognized binary patch at line %d: %.*s",
1018-
linenr-1, llen-1, buffer);
1057+
return NULL;
1058+
1059+
linenr++;
10191060
buffer += llen;
10201061
while (1) {
10211062
int byte_length, max_byte_length, newsize;
@@ -1044,21 +1085,79 @@ static int parse_binary(char *buffer, unsigned long size, struct patch *patch)
10441085
if (max_byte_length < byte_length ||
10451086
byte_length <= max_byte_length - 4)
10461087
goto corrupt;
1047-
newsize = fragment->size + byte_length;
1088+
newsize = hunk_size + byte_length;
10481089
data = xrealloc(data, newsize);
1049-
if (decode_85(data + fragment->size,
1050-
buffer + 1,
1051-
byte_length))
1090+
if (decode_85(data + hunk_size, buffer + 1, byte_length))
10521091
goto corrupt;
1053-
fragment->size = newsize;
1092+
hunk_size = newsize;
10541093
buffer += llen;
10551094
size -= llen;
10561095
}
1057-
fragment->patch = data;
1058-
return used;
1096+
1097+
frag = xcalloc(1, sizeof(*frag));
1098+
frag->patch = inflate_it(data, hunk_size, origlen);
1099+
if (!frag->patch)
1100+
goto corrupt;
1101+
free(data);
1102+
frag->size = origlen;
1103+
*buf_p = buffer;
1104+
*sz_p = size;
1105+
*used_p = used;
1106+
frag->binary_patch_method = patch_method;
1107+
return frag;
1108+
10591109
corrupt:
1060-
return error("corrupt binary patch at line %d: %.*s",
1061-
linenr-1, llen-1, buffer);
1110+
if (data)
1111+
free(data);
1112+
*status_p = -1;
1113+
error("corrupt binary patch at line %d: %.*s",
1114+
linenr-1, llen-1, buffer);
1115+
return NULL;
1116+
}
1117+
1118+
static int parse_binary(char *buffer, unsigned long size, struct patch *patch)
1119+
{
1120+
/* We have read "GIT binary patch\n"; what follows is a line
1121+
* that says the patch method (currently, either "literal" or
1122+
* "delta") and the length of data before deflating; a
1123+
* sequence of 'length-byte' followed by base-85 encoded data
1124+
* follows.
1125+
*
1126+
* When a binary patch is reversible, there is another binary
1127+
* hunk in the same format, starting with patch method (either
1128+
* "literal" or "delta") with the length of data, and a sequence
1129+
* of length-byte + base-85 encoded data, terminated with another
1130+
* empty line. This data, when applied to the postimage, produces
1131+
* the preimage.
1132+
*/
1133+
struct fragment *forward;
1134+
struct fragment *reverse;
1135+
int status;
1136+
int used, used_1;
1137+
1138+
forward = parse_binary_hunk(&buffer, &size, &status, &used);
1139+
if (!forward && !status)
1140+
/* there has to be one hunk (forward hunk) */
1141+
return error("unrecognized binary patch at line %d", linenr-1);
1142+
if (status)
1143+
/* otherwise we already gave an error message */
1144+
return status;
1145+
1146+
reverse = parse_binary_hunk(&buffer, &size, &status, &used_1);
1147+
if (reverse)
1148+
used += used_1;
1149+
else if (status) {
1150+
/* not having reverse hunk is not an error, but having
1151+
* a corrupt reverse hunk is.
1152+
*/
1153+
free((void*) forward->patch);
1154+
free(forward);
1155+
return status;
1156+
}
1157+
forward->next = reverse;
1158+
patch->fragments = forward;
1159+
patch->is_binary = 1;
1160+
return used;
10621161
}
10631162

10641163
static int parse_chunk(char *buffer, unsigned long size, struct patch *patch)
@@ -1505,59 +1604,36 @@ static int apply_one_fragment(struct buffer_desc *desc, struct fragment *frag, i
15051604
return offset;
15061605
}
15071606

1508-
static char *inflate_it(const void *data, unsigned long size,
1509-
unsigned long inflated_size)
1510-
{
1511-
z_stream stream;
1512-
void *out;
1513-
int st;
1514-
1515-
memset(&stream, 0, sizeof(stream));
1516-
1517-
stream.next_in = (unsigned char *)data;
1518-
stream.avail_in = size;
1519-
stream.next_out = out = xmalloc(inflated_size);
1520-
stream.avail_out = inflated_size;
1521-
inflateInit(&stream);
1522-
st = inflate(&stream, Z_FINISH);
1523-
if ((st != Z_STREAM_END) || stream.total_out != inflated_size) {
1524-
free(out);
1525-
return NULL;
1526-
}
1527-
return out;
1528-
}
1529-
15301607
static int apply_binary_fragment(struct buffer_desc *desc, struct patch *patch)
15311608
{
15321609
unsigned long dst_size;
15331610
struct fragment *fragment = patch->fragments;
15341611
void *data;
15351612
void *result;
15361613

1537-
/* Binary patch is irreversible */
1538-
if (apply_in_reverse)
1539-
return error("cannot reverse-apply a binary patch to '%s'",
1540-
patch->new_name
1541-
? patch->new_name : patch->old_name);
1542-
1543-
data = inflate_it(fragment->patch, fragment->size,
1544-
patch->deflate_origlen);
1545-
if (!data)
1546-
return error("corrupt patch data");
1547-
switch (patch->is_binary) {
1614+
/* Binary patch is irreversible without the optional second hunk */
1615+
if (apply_in_reverse) {
1616+
if (!fragment->next)
1617+
return error("cannot reverse-apply a binary patch "
1618+
"without the reverse hunk to '%s'",
1619+
patch->new_name
1620+
? patch->new_name : patch->old_name);
1621+
fragment = fragment;
1622+
}
1623+
data = (void*) fragment->patch;
1624+
switch (fragment->binary_patch_method) {
15481625
case BINARY_DELTA_DEFLATED:
15491626
result = patch_delta(desc->buffer, desc->size,
15501627
data,
1551-
patch->deflate_origlen,
1628+
fragment->size,
15521629
&dst_size);
15531630
free(desc->buffer);
15541631
desc->buffer = result;
1555-
free(data);
15561632
break;
15571633
case BINARY_LITERAL_DEFLATED:
15581634
free(desc->buffer);
15591635
desc->buffer = data;
1560-
dst_size = patch->deflate_origlen;
1636+
dst_size = fragment->size;
15611637
break;
15621638
}
15631639
if (!desc->buffer)

0 commit comments

Comments
 (0)