diff --git a/builtin-apply.c b/builtin-apply.c
index 8b8705a6c056f160940566ef2c851a09cbd98532..86d89a4a7e9240a75e1500bba524acdcec7f14d2 100644 (file)
--- a/builtin-apply.c
+++ b/builtin-apply.c
} new_whitespace = warn_on_whitespace;
static int whitespace_error;
static int squelch_whitespace_errors = 5;
} new_whitespace = warn_on_whitespace;
static int whitespace_error;
static int squelch_whitespace_errors = 5;
-static int applied_after_stripping;
+static int applied_after_fixing_ws;
static const char *patch_input_file;
static void parse_whitespace_option(const char *option)
static const char *patch_input_file;
static void parse_whitespace_option(const char *option)
void *buffer = xmalloc(alloc);
for (;;) {
void *buffer = xmalloc(alloc);
for (;;) {
- int nr = alloc - size;
+ ssize_t nr = alloc - size;
if (nr < 1024) {
alloc += CHUNKSIZE;
buffer = xrealloc(buffer, alloc);
if (nr < 1024) {
alloc += CHUNKSIZE;
buffer = xrealloc(buffer, alloc);
if (name) {
char *cp = name;
while (p_value) {
if (name) {
char *cp = name;
while (p_value) {
- cp = strchr(name, '/');
+ cp = strchr(cp, '/');
if (!cp)
break;
cp++;
if (!cp)
break;
cp++;
@@ -1003,12 +1003,16 @@ static int parse_fragment(char *line, unsigned long size, struct patch *patch, s
trailing++;
break;
case '-':
trailing++;
break;
case '-':
+ if (apply_in_reverse &&
+ new_whitespace != nowarn_whitespace)
+ check_whitespace(line, len);
deleted++;
oldlines--;
trailing = 0;
break;
case '+':
deleted++;
oldlines--;
trailing = 0;
break;
case '+':
- if (new_whitespace != nowarn_whitespace)
+ if (!apply_in_reverse &&
+ new_whitespace != nowarn_whitespace)
check_whitespace(line, len);
added++;
newlines--;
check_whitespace(line, len);
added++;
newlines--;
@@ -1468,7 +1472,7 @@ static int read_old_data(struct stat *st, const char *path, char **buf_p, unsign
return error("unable to open %s", path);
got = 0;
for (;;) {
return error("unable to open %s", path);
got = 0;
for (;;) {
- int ret = xread(fd, buf + got, size - got);
+ ssize_t ret = xread(fd, buf + got, size - got);
if (ret <= 0)
break;
got += ret;
if (ret <= 0)
break;
got += ret;
@@ -1510,7 +1514,8 @@ static int find_offset(const char *buf, unsigned long size, const char *fragment
}
/* Exact line number? */
}
/* Exact line number? */
- if (!memcmp(buf + start, fragment, fragsize))
+ if ((start + fragsize <= size) &&
+ !memcmp(buf + start, fragment, fragsize))
return start;
/*
return start;
/*
buf = output;
if (need_fix_leading_space) {
buf = output;
if (need_fix_leading_space) {
+ int consecutive_spaces = 0;
/* between patch[1..last_tab_in_indent] strip the
* funny spaces, updating them to tab as needed.
*/
for (i = 1; i < last_tab_in_indent; i++, plen--) {
char ch = patch[i];
/* between patch[1..last_tab_in_indent] strip the
* funny spaces, updating them to tab as needed.
*/
for (i = 1; i < last_tab_in_indent; i++, plen--) {
char ch = patch[i];
- if (ch != ' ')
+ if (ch != ' ') {
+ consecutive_spaces = 0;
*output++ = ch;
*output++ = ch;
- else if ((i % 8) == 0)
- *output++ = '\t';
+ } else {
+ consecutive_spaces++;
+ if (consecutive_spaces == 8) {
+ *output++ = '\t';
+ consecutive_spaces = 0;
+ }
+ }
}
fixed = 1;
i = last_tab_in_indent;
}
fixed = 1;
i = last_tab_in_indent;
if (add_nl_to_tail)
output[plen++] = '\n';
if (fixed)
if (add_nl_to_tail)
output[plen++] = '\n';
if (fixed)
- applied_after_stripping++;
+ applied_after_fixing_ws++;
return output + plen - buf;
}
return output + plen - buf;
}
@@ -1671,6 +1683,7 @@ static int apply_one_fragment(struct buffer_desc *desc, struct fragment *frag, i
char *new = xmalloc(size);
const char *oldlines, *newlines;
int oldsize = 0, newsize = 0;
char *new = xmalloc(size);
const char *oldlines, *newlines;
int oldsize = 0, newsize = 0;
+ int new_blank_lines_at_end = 0;
unsigned long leading, trailing;
int pos, lines;
unsigned long leading, trailing;
int pos, lines;
@@ -1678,6 +1691,7 @@ static int apply_one_fragment(struct buffer_desc *desc, struct fragment *frag, i
char first;
int len = linelen(patch, size);
int plen;
char first;
int len = linelen(patch, size);
int plen;
+ int added_blank_line = 0;
if (!len)
break;
if (!len)
break;
@@ -1699,6 +1713,7 @@ static int apply_one_fragment(struct buffer_desc *desc, struct fragment *frag, i
else if (first == '+')
first = '-';
}
else if (first == '+')
first = '-';
}
+
switch (first) {
case '\n':
/* Newer GNU diff, empty context line */
switch (first) {
case '\n':
/* Newer GNU diff, empty context line */
@@ -1716,9 +1731,14 @@ static int apply_one_fragment(struct buffer_desc *desc, struct fragment *frag, i
break;
/* Fall-through for ' ' */
case '+':
break;
/* Fall-through for ' ' */
case '+':
- if (first != '+' || !no_add)
- newsize += apply_line(new + newsize, patch,
- plen);
+ if (first != '+' || !no_add) {
+ int added = apply_line(new + newsize, patch,
+ plen);
+ newsize += added;
+ if (first == '+' &&
+ added == 1 && new[newsize-1] == '\n')
+ added_blank_line = 1;
+ }
break;
case '@': case '\\':
/* Ignore it, we already handled it */
break;
case '@': case '\\':
/* Ignore it, we already handled it */
@@ -1728,6 +1748,10 @@ static int apply_one_fragment(struct buffer_desc *desc, struct fragment *frag, i
error("invalid start of line: '%c'", first);
return -1;
}
error("invalid start of line: '%c'", first);
return -1;
}
+ if (added_blank_line)
+ new_blank_lines_at_end++;
+ else
+ new_blank_lines_at_end = 0;
patch += len;
size -= len;
}
patch += len;
size -= len;
}
@@ -1770,9 +1794,16 @@ static int apply_one_fragment(struct buffer_desc *desc, struct fragment *frag, i
if (match_beginning && offset)
offset = -1;
if (offset >= 0) {
if (match_beginning && offset)
offset = -1;
if (offset >= 0) {
- int diff = newsize - oldsize;
- unsigned long size = desc->size + diff;
- unsigned long alloc = desc->alloc;
+ int diff;
+ unsigned long size, alloc;
+
+ if (new_whitespace == strip_whitespace &&
+ (desc->size - oldsize - offset == 0)) /* end of file? */
+ newsize -= new_blank_lines_at_end;
+
+ diff = newsize - oldsize;
+ size = desc->size + diff;
+ alloc = desc->alloc;
/* Warn if it was necessary to reduce the number
* of context lines.
/* Warn if it was necessary to reduce the number
* of context lines.
return 0;
}
return 0;
}
+static int read_file_or_gitlink(struct cache_entry *ce, char **buf_p,
+ unsigned long *size_p)
+{
+ if (!ce)
+ return 0;
+
+ if (S_ISGITLINK(ntohl(ce->ce_mode))) {
+ *buf_p = xmalloc(100);
+ *size_p = snprintf(*buf_p, 100,
+ "Subproject commit %s\n", sha1_to_hex(ce->sha1));
+ } else {
+ enum object_type type;
+ *buf_p = read_sha1_file(ce->sha1, &type, size_p);
+ if (!*buf_p)
+ return -1;
+ }
+ return 0;
+}
+
static int apply_data(struct patch *patch, struct stat *st, struct cache_entry *ce)
{
char *buf;
static int apply_data(struct patch *patch, struct stat *st, struct cache_entry *ce)
{
char *buf;
@@ -1971,22 +2021,32 @@ static int apply_data(struct patch *patch, struct stat *st, struct cache_entry *
alloc = 0;
buf = NULL;
if (cached) {
alloc = 0;
buf = NULL;
if (cached) {
- if (ce) {
- enum object_type type;
- buf = read_sha1_file(ce->sha1, &type, &size);
- if (!buf)
+ if (read_file_or_gitlink(ce, &buf, &size))
+ return error("read of %s failed", patch->old_name);
+ alloc = size;
+ } else if (patch->old_name) {
+ if (S_ISGITLINK(patch->old_mode)) {
+ if (ce)
+ read_file_or_gitlink(ce, &buf, &size);
+ else {
+ /*
+ * There is no way to apply subproject
+ * patch without looking at the index.
+ */
+ patch->fragments = NULL;
+ size = 0;
+ }
+ }
+ else {
+ size = xsize_t(st->st_size);
+ alloc = size + 8192;
+ buf = xmalloc(alloc);
+ if (read_old_data(st, patch->old_name,
+ &buf, &alloc, &size))
return error("read of %s failed",
patch->old_name);
return error("read of %s failed",
patch->old_name);
- alloc = size;
}
}
}
}
- else if (patch->old_name) {
- size = xsize_t(st->st_size);
- alloc = size + 8192;
- buf = xmalloc(alloc);
- if (read_old_data(st, patch->old_name, &buf, &alloc, &size))
- return error("read of %s failed", patch->old_name);
- }
desc.size = size;
desc.alloc = alloc;
desc.size = size;
desc.alloc = alloc;
return 0;
}
return 0;
}
+static int verify_index_match(struct cache_entry *ce, struct stat *st)
+{
+ if (S_ISGITLINK(ntohl(ce->ce_mode))) {
+ if (!S_ISDIR(st->st_mode))
+ return -1;
+ return 0;
+ }
+ return ce_match_stat(ce, st, 1);
+}
+
static int check_patch(struct patch *patch, struct patch *prev_patch)
{
struct stat st;
static int check_patch(struct patch *patch, struct patch *prev_patch)
{
struct stat st;
int ok_if_exists;
patch->rejected = 1; /* we will drop this after we succeed */
int ok_if_exists;
patch->rejected = 1; /* we will drop this after we succeed */
+
+ /*
+ * Make sure that we do not have local modifications from the
+ * index when we are looking at the index. Also make sure
+ * we have the preimage file to be patched in the work tree,
+ * unless --cached, which tells git to apply only in the index.
+ */
if (old_name) {
if (old_name) {
- int changed = 0;
int stat_ret = 0;
unsigned st_mode = 0;
int stat_ret = 0;
unsigned st_mode = 0;
lstat(old_name, &st))
return -1;
}
lstat(old_name, &st))
return -1;
}
- if (!cached)
- changed = ce_match_stat(ce, &st, 1);
- if (changed)
+ if (!cached && verify_index_match(ce, &st))
return error("%s: does not match index",
old_name);
if (cached)
st_mode = ntohl(ce->ce_mode);
return error("%s: does not match index",
old_name);
if (cached)
st_mode = ntohl(ce->ce_mode);
- }
- else if (stat_ret < 0)
+ } else if (stat_ret < 0)
return error("%s: %s", old_name, strerror(errno));
if (!cached)
return error("%s: %s", old_name, strerror(errno));
if (!cached)
return err;
}
return err;
}
+/* This function tries to read the sha1 from the current index */
+static int get_current_sha1(const char *path, unsigned char *sha1)
+{
+ int pos;
+
+ if (read_cache() < 0)
+ return -1;
+ pos = cache_name_pos(path, strlen(path));
+ if (pos < 0)
+ return -1;
+ hashcpy(sha1, active_cache[pos]->sha1);
+ return 0;
+}
+
static void show_index_list(struct patch *list)
{
struct patch *patch;
static void show_index_list(struct patch *list)
{
struct patch *patch;
if (0 < patch->is_new)
sha1_ptr = null_sha1;
else if (get_sha1(patch->old_sha1_prefix, sha1))
if (0 < patch->is_new)
sha1_ptr = null_sha1;
else if (get_sha1(patch->old_sha1_prefix, sha1))
- die("sha1 information is lacking or useless (%s).",
- name);
+ /* git diff has no index line for mode/type changes */
+ if (!patch->lines_added && !patch->lines_deleted) {
+ if (get_current_sha1(patch->new_name, sha1) ||
+ get_current_sha1(patch->old_name, sha1))
+ die("mode change for %s, which is not "
+ "in current HEAD", name);
+ sha1_ptr = sha1;
+ } else
+ die("sha1 information is lacking or useless "
+ "(%s).", name);
else
sha1_ptr = sha1;
else
sha1_ptr = sha1;
if (update_index) {
if (remove_file_from_cache(patch->old_name) < 0)
die("unable to remove %s from index", patch->old_name);
if (update_index) {
if (remove_file_from_cache(patch->old_name) < 0)
die("unable to remove %s from index", patch->old_name);
- cache_tree_invalidate_path(active_cache_tree, patch->old_name);
}
if (!cached) {
}
if (!cached) {
- if (!unlink(patch->old_name) && rmdir_empty) {
+ if (S_ISGITLINK(patch->old_mode)) {
+ if (rmdir(patch->old_name))
+ warning("unable to remove submodule %s",
+ patch->old_name);
+ } else if (!unlink(patch->old_name) && rmdir_empty) {
char *name = xstrdup(patch->old_name);
char *end = strrchr(name, '/');
while (end) {
char *name = xstrdup(patch->old_name);
char *end = strrchr(name, '/');
while (end) {
@@ -2359,13 +2457,21 @@ static void add_index_file(const char *path, unsigned mode, void *buf, unsigned
memcpy(ce->name, path, namelen);
ce->ce_mode = create_ce_mode(mode);
ce->ce_flags = htons(namelen);
memcpy(ce->name, path, namelen);
ce->ce_mode = create_ce_mode(mode);
ce->ce_flags = htons(namelen);
- if (!cached) {
- if (lstat(path, &st) < 0)
- die("unable to stat newly created file %s", path);
- fill_stat_cache_info(ce, &st);
+ if (S_ISGITLINK(mode)) {
+ const char *s = buf;
+
+ if (get_sha1_hex(s + strlen("Subproject commit "), ce->sha1))
+ die("corrupt patch for subproject %s", path);
+ } else {
+ if (!cached) {
+ if (lstat(path, &st) < 0)
+ die("unable to stat newly created file %s",
+ path);
+ fill_stat_cache_info(ce, &st);
+ }
+ if (write_sha1_file(buf, size, blob_type, ce->sha1) < 0)
+ die("unable to create backing store for newly created file %s", path);
}
}
- if (write_sha1_file(buf, size, blob_type, ce->sha1) < 0)
- die("unable to create backing store for newly created file %s", path);
if (add_cache_entry(ce, ADD_CACHE_OK_TO_ADD) < 0)
die("unable to add cache entry for %s", path);
}
if (add_cache_entry(ce, ADD_CACHE_OK_TO_ADD) < 0)
die("unable to add cache entry for %s", path);
}
@@ -2375,6 +2481,13 @@ static int try_create_file(const char *path, unsigned int mode, const char *buf,
int fd;
char *nbuf;
int fd;
char *nbuf;
+ if (S_ISGITLINK(mode)) {
+ struct stat st;
+ if (!lstat(path, &st) && S_ISDIR(st.st_mode))
+ return 0;
+ return mkdir(path, 0777);
+ }
+
if (has_symlinks && S_ISLNK(mode))
/* Although buf:size is counted string, it also is NUL
* terminated.
if (has_symlinks && S_ISLNK(mode))
/* Although buf:size is counted string, it also is NUL
* terminated.
mode = S_IFREG | 0644;
create_one_file(path, mode, buf, size);
add_index_file(path, mode, buf, size);
mode = S_IFREG | 0644;
create_one_file(path, mode, buf, size);
add_index_file(path, mode, buf, size);
- cache_tree_invalidate_path(active_cache_tree, path);
}
/* phase zero is to remove, phase one is to create */
}
/* phase zero is to remove, phase one is to create */
* thing: remove the old, write the new
*/
if (phase == 0)
* thing: remove the old, write the new
*/
if (phase == 0)
- remove_file(patch, 0);
+ remove_file(patch, patch->is_rename);
if (phase == 1)
create_file(patch);
}
if (phase == 1)
create_file(patch);
}
squelched == 1 ? "" : "s");
}
if (new_whitespace == error_on_whitespace)
squelched == 1 ? "" : "s");
}
if (new_whitespace == error_on_whitespace)
- die("%d line%s add%s trailing whitespaces.",
+ die("%d line%s add%s whitespace errors.",
whitespace_error,
whitespace_error == 1 ? "" : "s",
whitespace_error == 1 ? "s" : "");
whitespace_error,
whitespace_error == 1 ? "" : "s",
whitespace_error == 1 ? "s" : "");
- if (applied_after_stripping)
+ if (applied_after_fixing_ws)
fprintf(stderr, "warning: %d line%s applied after"
fprintf(stderr, "warning: %d line%s applied after"
- " stripping trailing whitespaces.\n",
- applied_after_stripping,
- applied_after_stripping == 1 ? "" : "s");
+ " fixing whitespace errors.\n",
+ applied_after_fixing_ws,
+ applied_after_fixing_ws == 1 ? "" : "s");
else if (whitespace_error)
else if (whitespace_error)
- fprintf(stderr, "warning: %d line%s add%s trailing"
- " whitespaces.\n",
+ fprintf(stderr, "warning: %d line%s add%s whitespace errors.\n",
whitespace_error,
whitespace_error == 1 ? "" : "s",
whitespace_error == 1 ? "s" : "");
whitespace_error,
whitespace_error == 1 ? "" : "s",
whitespace_error == 1 ? "s" : "");