#include "delta.h"
#include "builtin.h"
-// --check turns on checking that the working tree matches the
-// files that are being modified, but doesn't apply the patch
-// --stat does just a diffstat, and doesn't actually apply
-// --numstat does numeric diffstat, and doesn't actually apply
-// --index-info shows the old and new index info for paths if available.
-// --index updates the cache as well.
-// --cached updates only the cache without ever touching the working tree.
-//
+/*
+ * --check turns on checking that the working tree matches the
+ * files that are being modified, but doesn't apply the patch
+ * --stat does just a diffstat, and doesn't actually apply
+ * --numstat does numeric diffstat, and doesn't actually apply
+ * --index-info shows the old and new index info for paths if available.
+ * --index updates the cache as well.
+ * --cached updates only the cache without ever touching the working tree.
+ */
static const char *prefix;
static int prefix_length = -1;
static int newfd = -1;
unsigned long deflate_origlen;
int lines_added, lines_deleted;
int score;
+ int inaccurate_eof:1;
struct fragment *fragments;
char *result;
unsigned long resultsize;
buffer = xrealloc(buffer, alloc);
nr = alloc - size;
}
- nr = xread(fd, buffer + size, nr);
+ nr = xread(fd, (char *) buffer + size, nr);
if (!nr)
break;
if (nr < 0)
*/
if (alloc < size + SLOP)
buffer = xrealloc(buffer, size + SLOP);
- memset(buffer + size, 0, SLOP);
+ memset((char *) buffer + size, 0, SLOP);
return buffer;
}
{
char *name;
- first += 4; // skip "--- "
- second += 4; // skip "+++ "
+ first += 4; /* skip "--- " */
+ second += 4; /* skip "+++ " */
if (is_dev_null(first)) {
patch->is_new = 1;
patch->is_delete = 0;
continue;
/*
- * Make sure we don't find any unconnected patch fragmants.
+ * Make sure we don't find any unconnected patch fragments.
* That's a sign that we didn't find a header, and that a
* patch has become corrupted/broken up.
*/
* 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 signalled with an empty line.
+ * The end of binary is signaled with an empty line.
*/
int llen, used;
struct fragment *fragment;
return error("unable to open %s", path);
got = 0;
for (;;) {
- int ret = xread(fd, buf + got, size - got);
+ int ret = xread(fd, (char *) buf + got, size - got);
if (ret <= 0)
break;
got += ret;
return plen;
}
-static int apply_one_fragment(struct buffer_desc *desc, struct fragment *frag)
+static int apply_one_fragment(struct buffer_desc *desc, struct fragment *frag,
+ int inaccurate_eof)
{
+ int match_beginning, match_end;
char *buf = desc->buffer;
const char *patch = frag->patch;
int offset, size = frag->size;
size -= len;
}
-#ifdef NO_ACCURATE_DIFF
- if (oldsize > 0 && old[oldsize - 1] == '\n' &&
+ if (inaccurate_eof && oldsize > 0 && old[oldsize - 1] == '\n' &&
newsize > 0 && new[newsize - 1] == '\n') {
oldsize--;
newsize--;
}
-#endif
oldlines = old;
newlines = new;
leading = frag->leading;
trailing = frag->trailing;
+
+ /*
+ * If we don't have any leading/trailing data in the patch,
+ * we want it to match at the beginning/end of the file.
+ */
+ match_beginning = !leading && (frag->oldpos == 1);
+ match_end = !trailing;
+
lines = 0;
pos = frag->newpos;
for (;;) {
offset = find_offset(buf, desc->size, oldlines, oldsize, pos, &lines);
+ if (match_end && offset + oldsize != desc->size)
+ offset = -1;
+ if (match_beginning && offset)
+ offset = -1;
if (offset >= 0) {
int diff = newsize - oldsize;
unsigned long size = desc->size + diff;
/* Am I at my context limits? */
if ((leading <= p_context) && (trailing <= p_context))
break;
+ if (match_beginning || match_end) {
+ match_beginning = match_end = 0;
+ continue;
+ }
/* Reduce the number of context lines
* Reduce both leading and trailing if they are equal
* otherwise just reduce the larger context.
return apply_binary(desc, patch);
while (frag) {
- if (apply_one_fragment(desc, frag) < 0)
+ if (apply_one_fragment(desc, frag, patch->inaccurate_eof) < 0)
return error("patch failed: %s:%ld",
name, frag->oldpos);
frag = frag->next;
return 0;
}
-static int check_patch(struct patch *patch)
+static int check_patch(struct patch *patch, struct patch *prev_patch)
{
struct stat st;
const char *old_name = patch->old_name;
const char *new_name = patch->new_name;
const char *name = old_name ? old_name : new_name;
struct cache_entry *ce = NULL;
+ int ok_if_exists;
if (old_name) {
int changed = 0;
old_name, st_mode, patch->old_mode);
}
+ if (new_name && prev_patch && prev_patch->is_delete &&
+ !strcmp(prev_patch->old_name, new_name))
+ /* A type-change diff is always split into a patch to
+ * delete old, immediately followed by a patch to
+ * create new (see diff.c::run_diff()); in such a case
+ * it is Ok that the entry to be deleted by the
+ * previous patch is still in the working tree and in
+ * the index.
+ */
+ ok_if_exists = 1;
+ else
+ ok_if_exists = 0;
+
if (new_name && (patch->is_new | patch->is_rename | patch->is_copy)) {
- if (check_index && cache_name_pos(new_name, strlen(new_name)) >= 0)
+ if (check_index &&
+ cache_name_pos(new_name, strlen(new_name)) >= 0 &&
+ !ok_if_exists)
return error("%s: already exists in index", new_name);
if (!cached) {
- if (!lstat(new_name, &st))
- return error("%s: already exists in working directory", new_name);
- if (errno != ENOENT)
+ struct stat nst;
+ if (!lstat(new_name, &nst)) {
+ if (S_ISDIR(nst.st_mode) || ok_if_exists)
+ ; /* ok */
+ else
+ return error("%s: already exists in working directory", new_name);
+ }
+ else if ((errno != ENOENT) && (errno != ENOTDIR))
return error("%s: %s", new_name, strerror(errno));
}
if (!patch->new_mode) {
static int check_patch_list(struct patch *patch)
{
+ struct patch *prev_patch = NULL;
int error = 0;
- for (;patch ; patch = patch->next)
- error |= check_patch(patch);
+ for (prev_patch = NULL; patch ; patch = patch->next) {
+ error |= check_patch(patch, prev_patch);
+ prev_patch = patch;
+ }
return error;
}
return;
}
+ if (errno == EEXIST || errno == EACCES) {
+ /* We may be trying to create a file where a directory
+ * used to be.
+ */
+ struct stat st;
+ errno = 0;
+ if (!lstat(path, &st) && S_ISDIR(st.st_mode) && !rmdir(path))
+ errno = EEXIST;
+ }
+
if (errno == EEXIST) {
unsigned int nr = getpid();
cache_tree_invalidate_path(active_cache_tree, path);
}
-static void write_out_one_result(struct patch *patch)
+/* phase zero is to remove, phase one is to create */
+static void write_out_one_result(struct patch *patch, int phase)
{
if (patch->is_delete > 0) {
- remove_file(patch);
+ if (phase == 0)
+ remove_file(patch);
return;
}
if (patch->is_new > 0 || patch->is_copy) {
- create_file(patch);
+ if (phase == 1)
+ create_file(patch);
return;
}
/*
* Rename or modification boils down to the same
* thing: remove the old, write the new
*/
- remove_file(patch);
+ if (phase == 0)
+ remove_file(patch);
+ if (phase == 1)
create_file(patch);
}
static void write_out_results(struct patch *list, int skipped_patch)
{
+ int phase;
+
if (!list && !skipped_patch)
die("No changes");
- while (list) {
- write_out_one_result(list);
- list = list->next;
+ for (phase = 0; phase < 2; phase++) {
+ struct patch *l = list;
+ while (l) {
+ write_out_one_result(l, phase);
+ l = l->next;
+ }
}
}
-static struct cache_file cache_file;
+static struct lock_file lock_file;
static struct excludes {
struct excludes *next;
return 1;
}
-static int apply_patch(int fd, const char *filename)
+static int apply_patch(int fd, const char *filename, int inaccurate_eof)
{
unsigned long offset, size;
char *buffer = read_patch_file(fd, &size);
int nr;
patch = xcalloc(1, sizeof(*patch));
+ patch->inaccurate_eof = inaccurate_eof;
nr = parse_chunk(buffer + offset, size, patch);
if (nr < 0)
break;
apply = 0;
write_index = check_index && apply;
- if (write_index && newfd < 0)
- newfd = hold_index_file_for_update(&cache_file, get_index_file());
+ 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");
+ }
if (check_index) {
if (read_cache() < 0)
die("unable to read index file");
{
int i;
int read_stdin = 1;
+ int inaccurate_eof = 0;
+
const char *whitespace_option = NULL;
for (i = 1; i < argc; i++) {
int fd;
if (!strcmp(arg, "-")) {
- apply_patch(0, "<stdin>");
+ apply_patch(0, "<stdin>", inaccurate_eof);
read_stdin = 0;
continue;
}
parse_whitespace_option(arg + 13);
continue;
}
+ if (!strcmp(arg, "--inaccurate-eof")) {
+ inaccurate_eof = 1;
+ continue;
+ }
if (check_index && prefix_length < 0) {
prefix = setup_git_directory();
usage(apply_usage);
read_stdin = 0;
set_default_whitespace_mode(whitespace_option);
- apply_patch(fd, arg);
+ apply_patch(fd, arg, inaccurate_eof);
close(fd);
}
set_default_whitespace_mode(whitespace_option);
if (read_stdin)
- apply_patch(0, "<stdin>");
+ apply_patch(0, "<stdin>", inaccurate_eof);
if (whitespace_error) {
if (squelch_whitespace_errors &&
squelch_whitespace_errors < whitespace_error) {
if (write_index) {
if (write_cache(newfd, active_cache, active_nr) ||
- commit_index_file(&cache_file))
- die("Unable to write new cachefile");
+ close(newfd) || commit_lock_file(&lock_file))
+ die("Unable to write new index file");
}
return 0;