static int newfd = -1;
static int p_value = 1;
-static int allow_binary_replacement = 0;
-static int check_index = 0;
-static int write_index = 0;
-static int cached = 0;
-static int diffstat = 0;
-static int numstat = 0;
-static int summary = 0;
-static int check = 0;
+static int allow_binary_replacement;
+static int check_index;
+static int write_index;
+static int cached;
+static int diffstat;
+static int numstat;
+static int summary;
+static int check;
static int apply = 1;
-static int no_add = 0;
-static int show_index_info = 0;
+static int apply_in_reverse;
+static int apply_with_reject;
+static int apply_verbosely;
+static int no_add;
+static int show_index_info;
static int line_termination = '\n';
static unsigned long p_context = -1;
static const char apply_usage[] =
-"git-apply [--stat] [--numstat] [--summary] [--check] [--index] [--cached] [--apply] [--no-add] [--index-info] [--allow-binary-replacement] [-z] [-pNUM] [-CNUM] [--whitespace=<nowarn|warn|error|error-all|strip>] <patch>...";
+"git-apply [--stat] [--numstat] [--summary] [--check] [--index] [--cached] [--apply] [--no-add] [--index-info] [--allow-binary-replacement] [--reverse] [--reject] [--verbose] [-z] [-pNUM] [-CNUM] [--whitespace=<nowarn|warn|error|error-all|strip>] <patch>...";
static enum whitespace_eol {
nowarn_whitespace,
error_on_whitespace,
strip_whitespace,
} new_whitespace = warn_on_whitespace;
-static int whitespace_error = 0;
+static int whitespace_error;
static int squelch_whitespace_errors = 5;
-static int applied_after_stripping = 0;
-static const char *patch_input_file = NULL;
+static int applied_after_stripping;
+static const char *patch_input_file;
static void parse_whitespace_option(const char *option)
{
*/
static int linenr = 1;
+/*
+ * This represents one "hunk" from a patch, starting with
+ * "@@ -oldpos,oldlines +newpos,newlines @@" marker. The
+ * patch text is pointed at by patch, and its byte length
+ * is stored in size. leading and trailing are the number
+ * of context lines.
+ */
struct fragment {
unsigned long leading, trailing;
unsigned long oldpos, oldlines;
unsigned long newpos, newlines;
const char *patch;
int size;
+ int rejected;
struct fragment *next;
};
+/*
+ * When dealing with a binary patch, we reuse "leading" field
+ * to store the type of the binary hunk, either deflated "delta"
+ * or deflated "literal".
+ */
+#define binary_patch_method leading
+#define BINARY_DELTA_DEFLATED 1
+#define BINARY_LITERAL_DEFLATED 2
+
struct patch {
char *new_name, *old_name, *def_name;
unsigned int old_mode, new_mode;
- int is_rename, is_copy, is_new, is_delete, is_binary, is_reverse;
-#define BINARY_DELTA_DEFLATED 1
-#define BINARY_LITERAL_DEFLATED 2
+ int is_rename, is_copy, is_new, is_delete, is_binary;
+ int rejected;
unsigned long deflate_origlen;
int lines_added, lines_deleted;
int score;
struct patch *next;
};
+static void say_patch_name(FILE *output, const char *pre, struct patch *patch, const char *post)
+{
+ fputs(pre, output);
+ if (patch->old_name && patch->new_name &&
+ strcmp(patch->old_name, patch->new_name)) {
+ write_name_quoted(NULL, 0, patch->old_name, 1, output);
+ fputs(" => ", output);
+ write_name_quoted(NULL, 0, patch->new_name, 1, output);
+ }
+ else {
+ const char *n = patch->new_name;
+ if (!n)
+ n = patch->old_name;
+ write_name_quoted(NULL, 0, n, 1, output);
+ }
+ fputs(post, output);
+}
+
#define CHUNKSIZE (8192)
#define SLOP (16)
* form.
*/
for (len = 0 ; ; len++) {
- char c = name[len];
-
- switch (c) {
+ switch (name[len]) {
default:
continue;
case '\n':
patch->old_mode != patch->new_mode);
}
-static int parse_binary(char *buffer, unsigned long size, struct patch *patch)
+static char *inflate_it(const void *data, unsigned long size,
+ unsigned long inflated_size)
{
- /* We have read "GIT binary patch\n"; what follows is a line
- * that says the patch method (currently, either "deflated
- * literal" or "deflated delta") and the length of data before
- * deflating; a sequence of 'length-byte' followed by base-85
- * encoded data follows.
+ z_stream stream;
+ void *out;
+ int st;
+
+ memset(&stream, 0, sizeof(stream));
+
+ stream.next_in = (unsigned char *)data;
+ stream.avail_in = size;
+ stream.next_out = out = xmalloc(inflated_size);
+ stream.avail_out = inflated_size;
+ inflateInit(&stream);
+ st = inflate(&stream, Z_FINISH);
+ if ((st != Z_STREAM_END) || stream.total_out != inflated_size) {
+ free(out);
+ return NULL;
+ }
+ return out;
+}
+
+static struct fragment *parse_binary_hunk(char **buf_p,
+ unsigned long *sz_p,
+ int *status_p,
+ int *used_p)
+{
+ /* Expect a line that begins with binary patch method ("literal"
+ * or "delta"), followed by the length of data before deflating.
+ * a sequence of 'length-byte' followed by base-85 encoded data
+ * should follow, terminated by a newline.
*
* Each 5-byte sequence of base-85 encodes up to 4 bytes,
* and we would limit the patch line to 66 characters,
* so one line can fit up to 13 groups that would decode
* to 52 bytes max. The length byte 'A'-'Z' corresponds
* to 1-26 bytes, and 'a'-'z' corresponds to 27-52 bytes.
- * The end of binary is signaled with an empty line.
*/
int llen, used;
- struct fragment *fragment;
+ unsigned long size = *sz_p;
+ char *buffer = *buf_p;
+ int patch_method;
+ unsigned long origlen;
char *data = NULL;
+ int hunk_size = 0;
+ struct fragment *frag;
- patch->fragments = fragment = xcalloc(1, sizeof(*fragment));
-
- /* Grab the type of patch */
llen = linelen(buffer, size);
used = llen;
- linenr++;
+
+ *status_p = 0;
if (!strncmp(buffer, "delta ", 6)) {
- patch->is_binary = BINARY_DELTA_DEFLATED;
- patch->deflate_origlen = strtoul(buffer + 6, NULL, 10);
+ patch_method = BINARY_DELTA_DEFLATED;
+ origlen = strtoul(buffer + 6, NULL, 10);
}
else if (!strncmp(buffer, "literal ", 8)) {
- patch->is_binary = BINARY_LITERAL_DEFLATED;
- patch->deflate_origlen = strtoul(buffer + 8, NULL, 10);
+ patch_method = BINARY_LITERAL_DEFLATED;
+ origlen = strtoul(buffer + 8, NULL, 10);
}
else
- return error("unrecognized binary patch at line %d: %.*s",
- linenr-1, llen-1, buffer);
+ return NULL;
+
+ linenr++;
buffer += llen;
while (1) {
int byte_length, max_byte_length, newsize;
llen = linelen(buffer, size);
used += llen;
linenr++;
- if (llen == 1)
+ if (llen == 1) {
+ /* consume the blank line */
+ buffer++;
+ size--;
break;
+ }
/* Minimum line is "A00000\n" which is 7-byte long,
* and the line length must be multiple of 5 plus 2.
*/
if (max_byte_length < byte_length ||
byte_length <= max_byte_length - 4)
goto corrupt;
- newsize = fragment->size + byte_length;
+ newsize = hunk_size + byte_length;
data = xrealloc(data, newsize);
- if (decode_85(data + fragment->size,
- buffer + 1,
- byte_length))
+ if (decode_85(data + hunk_size, buffer + 1, byte_length))
goto corrupt;
- fragment->size = newsize;
+ hunk_size = newsize;
buffer += llen;
size -= llen;
}
- fragment->patch = data;
- return used;
+
+ frag = xcalloc(1, sizeof(*frag));
+ frag->patch = inflate_it(data, hunk_size, origlen);
+ if (!frag->patch)
+ goto corrupt;
+ free(data);
+ frag->size = origlen;
+ *buf_p = buffer;
+ *sz_p = size;
+ *used_p = used;
+ frag->binary_patch_method = patch_method;
+ return frag;
+
corrupt:
- return error("corrupt binary patch at line %d: %.*s",
- linenr-1, llen-1, buffer);
+ free(data);
+ *status_p = -1;
+ error("corrupt binary patch at line %d: %.*s",
+ linenr-1, llen-1, buffer);
+ return NULL;
+}
+
+static int parse_binary(char *buffer, unsigned long size, struct patch *patch)
+{
+ /* We have read "GIT binary patch\n"; what follows is a line
+ * that says the patch method (currently, either "literal" or
+ * "delta") and the length of data before deflating; a
+ * sequence of 'length-byte' followed by base-85 encoded data
+ * follows.
+ *
+ * When a binary patch is reversible, there is another binary
+ * hunk in the same format, starting with patch method (either
+ * "literal" or "delta") with the length of data, and a sequence
+ * of length-byte + base-85 encoded data, terminated with another
+ * empty line. This data, when applied to the postimage, produces
+ * the preimage.
+ */
+ struct fragment *forward;
+ struct fragment *reverse;
+ int status;
+ int used, used_1;
+
+ forward = parse_binary_hunk(&buffer, &size, &status, &used);
+ if (!forward && !status)
+ /* there has to be one hunk (forward hunk) */
+ return error("unrecognized binary patch at line %d", linenr-1);
+ if (status)
+ /* otherwise we already gave an error message */
+ return status;
+
+ reverse = parse_binary_hunk(&buffer, &size, &status, &used_1);
+ if (reverse)
+ used += used_1;
+ else if (status) {
+ /* not having reverse hunk is not an error, but having
+ * a corrupt reverse hunk is.
+ */
+ free((void*) forward->patch);
+ free(forward);
+ return status;
+ }
+ forward->next = reverse;
+ patch->fragments = forward;
+ patch->is_binary = 1;
+ return used;
}
static int parse_chunk(char *buffer, unsigned long size, struct patch *patch)
swap(frag->newpos, frag->oldpos);
swap(frag->newlines, frag->oldlines);
}
- p->is_reverse = !p->is_reverse;
}
}
printf(" %s%-*s |%5d %.*s%.*s\n", prefix,
len, name, patch->lines_added + patch->lines_deleted,
add, pluses, del, minuses);
- if (qname)
- free(qname);
+ free(qname);
}
static int read_old_data(struct stat *st, const char *path, void *buf, unsigned long size)
return plen;
}
-static int apply_one_fragment(struct buffer_desc *desc, struct fragment *frag,
- int reverse, int inaccurate_eof)
+static int apply_one_fragment(struct buffer_desc *desc, struct fragment *frag, int inaccurate_eof)
{
int match_beginning, match_end;
char *buf = desc->buffer;
if (len < size && patch[len] == '\\')
plen--;
first = *patch;
- if (reverse) {
+ if (apply_in_reverse) {
if (first == '-')
first = '+';
else if (first == '+')
lines = 0;
pos = frag->newpos;
for (;;) {
- offset = find_offset(buf, desc->size, oldlines, oldsize, pos, &lines);
+ offset = find_offset(buf, desc->size,
+ oldlines, oldsize, pos, &lines);
if (match_end && offset + oldsize != desc->size)
offset = -1;
if (match_beginning && offset)
/* Warn if it was necessary to reduce the number
* of context lines.
*/
- if ((leading != frag->leading) || (trailing != frag->trailing))
- fprintf(stderr, "Context reduced to (%ld/%ld) to apply fragment at %d\n",
+ if ((leading != frag->leading) ||
+ (trailing != frag->trailing))
+ fprintf(stderr, "Context reduced to (%ld/%ld)"
+ " to apply fragment at %d\n",
leading, trailing, pos + lines);
if (size > alloc) {
desc->buffer = buf;
}
desc->size = size;
- memmove(buf + offset + newsize, buf + offset + oldsize, size - offset - newsize);
+ memmove(buf + offset + newsize,
+ buf + offset + oldsize,
+ size - offset - newsize);
memcpy(buf + offset, newlines, newsize);
offset = 0;
return offset;
}
-static char *inflate_it(const void *data, unsigned long size,
- unsigned long inflated_size)
-{
- z_stream stream;
- void *out;
- int st;
-
- memset(&stream, 0, sizeof(stream));
-
- stream.next_in = (unsigned char *)data;
- stream.avail_in = size;
- stream.next_out = out = xmalloc(inflated_size);
- stream.avail_out = inflated_size;
- inflateInit(&stream);
- st = inflate(&stream, Z_FINISH);
- if ((st != Z_STREAM_END) || stream.total_out != inflated_size) {
- free(out);
- return NULL;
- }
- return out;
-}
-
static int apply_binary_fragment(struct buffer_desc *desc, struct patch *patch)
{
unsigned long dst_size;
void *data;
void *result;
- /* Binary patch is irreversible */
- if (patch->is_reverse)
- return error("cannot reverse-apply a binary patch to '%s'",
- patch->new_name
- ? patch->new_name : patch->old_name);
-
- data = inflate_it(fragment->patch, fragment->size,
- patch->deflate_origlen);
- if (!data)
- return error("corrupt patch data");
- switch (patch->is_binary) {
+ /* Binary patch is irreversible without the optional second hunk */
+ if (apply_in_reverse) {
+ if (!fragment->next)
+ return error("cannot reverse-apply a binary patch "
+ "without the reverse hunk to '%s'",
+ patch->new_name
+ ? patch->new_name : patch->old_name);
+ fragment = fragment->next;
+ }
+ data = (void*) fragment->patch;
+ switch (fragment->binary_patch_method) {
case BINARY_DELTA_DEFLATED:
result = patch_delta(desc->buffer, desc->size,
data,
- patch->deflate_origlen,
+ fragment->size,
&dst_size);
free(desc->buffer);
desc->buffer = result;
- free(data);
break;
case BINARY_LITERAL_DEFLATED:
free(desc->buffer);
desc->buffer = data;
- dst_size = patch->deflate_origlen;
+ dst_size = fragment->size;
break;
}
if (!desc->buffer)
}
get_sha1_hex(patch->new_sha1_prefix, sha1);
- if (!memcmp(sha1, null_sha1, 20)) {
+ if (is_null_sha1(sha1)) {
free(desc->buffer);
desc->alloc = desc->size = 0;
desc->buffer = NULL;
write_sha1_file_prepare(desc->buffer, desc->size, blob_type,
sha1, hdr, &hdrlen);
if (strcmp(sha1_to_hex(sha1), patch->new_sha1_prefix))
- return error("binary patch to '%s' creates incorrect result", name);
+ return error("binary patch to '%s' creates incorrect result (expecting %s, got %s)", name, patch->new_sha1_prefix, sha1_to_hex(sha1));
}
return 0;
return apply_binary(desc, patch);
while (frag) {
- if (apply_one_fragment(desc, frag, patch->is_reverse,
- patch->inaccurate_eof) < 0)
- return error("patch failed: %s:%ld",
- name, frag->oldpos);
+ if (apply_one_fragment(desc, frag, patch->inaccurate_eof)) {
+ error("patch failed: %s:%ld", name, frag->oldpos);
+ if (!apply_with_reject)
+ return -1;
+ frag->rejected = 1;
+ }
frag = frag->next;
}
return 0;
desc.size = size;
desc.alloc = alloc;
desc.buffer = buf;
+
if (apply_fragments(&desc, patch) < 0)
- return -1;
+ return -1; /* note with --reject this succeeds. */
+
+ /* NUL terminate the result */
+ if (desc.alloc <= desc.size)
+ desc.buffer = xrealloc(desc.buffer, desc.size + 1);
+ desc.buffer[desc.size] = 0;
+
patch->result = desc.buffer;
patch->resultsize = desc.size;
struct cache_entry *ce = NULL;
int ok_if_exists;
+ patch->rejected = 1; /* we will drop this after we succeed */
if (old_name) {
int changed = 0;
int stat_ret = 0;
if (apply_data(patch, &st, ce) < 0)
return error("%s: patch does not apply", name);
+ patch->rejected = 0;
return 0;
}
static int check_patch_list(struct patch *patch)
{
struct patch *prev_patch = NULL;
- int error = 0;
+ int err = 0;
for (prev_patch = NULL; patch ; patch = patch->next) {
- error |= check_patch(patch, prev_patch);
+ if (apply_verbosely)
+ say_patch_name(stderr,
+ "Checking patch ", patch, "...\n");
+ err |= check_patch(patch, prev_patch);
prev_patch = patch;
}
- return error;
-}
-
-static inline int is_null_sha1(const unsigned char *sha1)
-{
- return !memcmp(sha1, null_sha1, 20);
+ return err;
}
static void show_index_list(struct patch *list)
int fd;
if (S_ISLNK(mode))
+ /* Although buf:size is counted string, it also is NUL
+ * terminated.
+ */
return symlink(buf, path);
fd = open(path, O_CREAT | O_EXCL | O_WRONLY, (mode & 0100) ? 0777 : 0666);
if (fd < 0)
if (phase == 0)
remove_file(patch);
if (phase == 1)
- create_file(patch);
+ create_file(patch);
}
-static void write_out_results(struct patch *list, int skipped_patch)
+static int write_out_one_reject(struct patch *patch)
+{
+ FILE *rej;
+ char namebuf[PATH_MAX];
+ struct fragment *frag;
+ int cnt = 0;
+
+ for (cnt = 0, frag = patch->fragments; frag; frag = frag->next) {
+ if (!frag->rejected)
+ continue;
+ cnt++;
+ }
+
+ if (!cnt) {
+ if (apply_verbosely)
+ say_patch_name(stderr,
+ "Applied patch ", patch, " cleanly.\n");
+ return 0;
+ }
+
+ /* This should not happen, because a removal patch that leaves
+ * contents are marked "rejected" at the patch level.
+ */
+ if (!patch->new_name)
+ die("internal error");
+
+ /* Say this even without --verbose */
+ say_patch_name(stderr, "Applying patch ", patch, " with");
+ fprintf(stderr, " %d rejects...\n", cnt);
+
+ cnt = strlen(patch->new_name);
+ if (ARRAY_SIZE(namebuf) <= cnt + 5) {
+ cnt = ARRAY_SIZE(namebuf) - 5;
+ fprintf(stderr,
+ "warning: truncating .rej filename to %.*s.rej",
+ cnt - 1, patch->new_name);
+ }
+ memcpy(namebuf, patch->new_name, cnt);
+ memcpy(namebuf + cnt, ".rej", 5);
+
+ rej = fopen(namebuf, "w");
+ if (!rej)
+ return error("cannot open %s: %s", namebuf, strerror(errno));
+
+ /* Normal git tools never deal with .rej, so do not pretend
+ * this is a git patch by saying --git nor give extended
+ * headers. While at it, maybe please "kompare" that wants
+ * the trailing TAB and some garbage at the end of line ;-).
+ */
+ fprintf(rej, "diff a/%s b/%s\t(rejected hunks)\n",
+ patch->new_name, patch->new_name);
+ for (cnt = 1, frag = patch->fragments;
+ frag;
+ cnt++, frag = frag->next) {
+ if (!frag->rejected) {
+ fprintf(stderr, "Hunk #%d applied cleanly.\n", cnt);
+ continue;
+ }
+ fprintf(stderr, "Rejected hunk #%d.\n", cnt);
+ fprintf(rej, "%.*s", frag->size, frag->patch);
+ if (frag->patch[frag->size-1] != '\n')
+ fputc('\n', rej);
+ }
+ fclose(rej);
+ return -1;
+}
+
+static int write_out_results(struct patch *list, int skipped_patch)
{
int phase;
+ int errs = 0;
+ struct patch *l;
if (!list && !skipped_patch)
- die("No changes");
+ return error("No changes");
for (phase = 0; phase < 2; phase++) {
- struct patch *l = list;
+ l = list;
while (l) {
- write_out_one_result(l, phase);
+ if (l->rejected)
+ errs = 1;
+ else {
+ write_out_one_result(l, phase);
+ if (phase == 1 && write_out_one_reject(l))
+ errs = 1;
+ }
l = l->next;
}
}
+ return errs;
}
static struct lock_file lock_file;
return 1;
}
-static int apply_patch(int fd, const char *filename,
- int reverse, int inaccurate_eof)
+static int apply_patch(int fd, const char *filename, int inaccurate_eof)
{
unsigned long offset, size;
char *buffer = read_patch_file(fd, &size);
nr = parse_chunk(buffer + offset, size, patch);
if (nr < 0)
break;
- if (reverse)
+ if (apply_in_reverse)
reverse_patches(patch);
if (use_patch(patch)) {
patch_stats(patch);
apply = 0;
write_index = check_index && apply;
- if (write_index && newfd < 0) {
+ if (write_index && newfd < 0)
newfd = hold_lock_file_for_update(&lock_file,
- get_index_file());
- if (newfd < 0)
- die("unable to create new index file");
- }
+ get_index_file(), 1);
if (check_index) {
if (read_cache() < 0)
die("unable to read index file");
}
- if ((check || apply) && check_patch_list(list) < 0)
+ if ((check || apply) &&
+ check_patch_list(list) < 0 &&
+ !apply_with_reject)
exit(1);
- if (apply)
- write_out_results(list, skipped_patch);
+ if (apply && write_out_results(list, skipped_patch))
+ exit(1);
if (show_index_info)
show_index_list(list);
}
-int cmd_apply(int argc, const char **argv, char **envp)
+int cmd_apply(int argc, const char **argv, const char *prefix)
{
int i;
int read_stdin = 1;
- int reverse = 0;
int inaccurate_eof = 0;
+ int errs = 0;
const char *whitespace_option = NULL;
int fd;
if (!strcmp(arg, "-")) {
- apply_patch(0, "<stdin>", reverse, inaccurate_eof);
+ errs |= apply_patch(0, "<stdin>", inaccurate_eof);
read_stdin = 0;
continue;
}
continue;
}
if (!strcmp(arg, "-R") || !strcmp(arg, "--reverse")) {
- reverse = 1;
+ apply_in_reverse = 1;
+ continue;
+ }
+ if (!strcmp(arg, "--reject")) {
+ apply = apply_with_reject = apply_verbosely = 1;
+ continue;
+ }
+ if (!strcmp(arg, "--verbose")) {
+ apply_verbosely = 1;
continue;
}
if (!strcmp(arg, "--inaccurate-eof")) {
usage(apply_usage);
read_stdin = 0;
set_default_whitespace_mode(whitespace_option);
- apply_patch(fd, arg, reverse, inaccurate_eof);
+ errs |= apply_patch(fd, arg, inaccurate_eof);
close(fd);
}
set_default_whitespace_mode(whitespace_option);
if (read_stdin)
- apply_patch(0, "<stdin>", reverse, inaccurate_eof);
+ errs |= apply_patch(0, "<stdin>", inaccurate_eof);
if (whitespace_error) {
if (squelch_whitespace_errors &&
squelch_whitespace_errors < whitespace_error) {
int squelched =
whitespace_error - squelch_whitespace_errors;
- fprintf(stderr, "warning: squelched %d whitespace error%s\n",
+ fprintf(stderr, "warning: squelched %d "
+ "whitespace error%s\n",
squelched,
squelched == 1 ? "" : "s");
}
die("Unable to write new index file");
}
- return 0;
+ return !!errs;
}