diff --git a/builtin-apply.c b/builtin-apply.c
index 2784db2efb5030c819f41b6c880f53e8876ec023..630d8fd6521a63320e59a5bd061720d1fc841e7a 100644 (file)
--- a/builtin-apply.c
+++ b/builtin-apply.c
static int unidiff_zero;
static int p_value = 1;
static int unidiff_zero;
static int p_value = 1;
+static int p_value_known;
static int check_index;
static int write_index;
static int cached;
static int check_index;
static int write_index;
static int cached;
unsigned long deflate_origlen;
int lines_added, lines_deleted;
int score;
unsigned long deflate_origlen;
int lines_added, lines_deleted;
int score;
+ unsigned int is_toplevel_relative:1;
unsigned int inaccurate_eof:1;
unsigned int is_binary:1;
unsigned int is_copy:1;
unsigned int inaccurate_eof:1;
unsigned int is_binary:1;
unsigned int is_copy:1;
return 1;
}
return 1;
}
-static char * find_name(const char *line, char *def, int p_value, int terminate)
+static char *find_name(const char *line, char *def, int p_value, int terminate)
{
int len;
const char *start = line;
{
int len;
const char *start = line;
@@ -311,11 +313,54 @@ static char * find_name(const char *line, char *def, int p_value, int terminate)
return name;
}
return name;
}
+static int count_slashes(const char *cp)
+{
+ int cnt = 0;
+ char ch;
+
+ while ((ch = *cp++))
+ if (ch == '/')
+ cnt++;
+ return cnt;
+}
+
+/*
+ * Given the string after "--- " or "+++ ", guess the appropriate
+ * p_value for the given patch.
+ */
+static int guess_p_value(const char *nameline)
+{
+ char *name, *cp;
+ int val = -1;
+
+ if (is_dev_null(nameline))
+ return -1;
+ name = find_name(nameline, NULL, 0, TERM_SPACE | TERM_TAB);
+ if (!name)
+ return -1;
+ cp = strchr(name, '/');
+ if (!cp)
+ val = 0;
+ else if (prefix) {
+ /*
+ * Does it begin with "a/$our-prefix" and such? Then this is
+ * very likely to apply to our directory.
+ */
+ if (!strncmp(name, prefix, prefix_length))
+ val = count_slashes(prefix);
+ else {
+ cp++;
+ if (!strncmp(cp, prefix, prefix_length))
+ val = count_slashes(prefix) + 1;
+ }
+ }
+ free(name);
+ return val;
+}
+
/*
* Get the name etc info from the --/+++ lines of a traditional patch header
*
/*
* Get the name etc info from the --/+++ lines of a traditional patch header
*
- * NOTE! This hardcodes "-p1" behaviour in filename detection.
- *
* FIXME! The end-of-filename heuristics are kind of screwy. For existing
* files, we can happily check the index for a match, but for creating a
* new file we should try to match whatever "patch" does. I have no idea.
* FIXME! The end-of-filename heuristics are kind of screwy. For existing
* files, we can happily check the index for a match, but for creating a
* new file we should try to match whatever "patch" does. I have no idea.
@@ -326,6 +371,16 @@ static void parse_traditional_patch(const char *first, const char *second, struc
first += 4; /* skip "--- " */
second += 4; /* skip "+++ " */
first += 4; /* skip "--- " */
second += 4; /* skip "+++ " */
+ if (!p_value_known) {
+ int p, q;
+ p = guess_p_value(first);
+ q = guess_p_value(second);
+ if (p < 0) p = q;
+ if (0 <= p && p == q) {
+ p_value = p;
+ p_value_known = 1;
+ }
+ }
if (is_dev_null(first)) {
patch->is_new = 1;
patch->is_delete = 0;
if (is_dev_null(first)) {
patch->is_new = 1;
patch->is_delete = 0;
@@ -787,6 +842,7 @@ static int find_header(char *line, unsigned long size, int *hdrsize, struct patc
{
unsigned long offset, len;
{
unsigned long offset, len;
+ patch->is_toplevel_relative = 0;
patch->is_rename = patch->is_copy = 0;
patch->is_new = patch->is_delete = -1;
patch->old_mode = patch->new_mode = 0;
patch->is_rename = patch->is_copy = 0;
patch->is_new = patch->is_delete = -1;
patch->old_mode = patch->new_mode = 0;
@@ -831,6 +887,7 @@ static int find_header(char *line, unsigned long size, int *hdrsize, struct patc
die("git diff header lacks filename information (line %d)", linenr);
patch->old_name = patch->new_name = patch->def_name;
}
die("git diff header lacks filename information (line %d)", linenr);
patch->old_name = patch->new_name = patch->def_name;
}
+ patch->is_toplevel_relative = 1;
*hdrsize = git_hdr_len;
return offset;
}
*hdrsize = git_hdr_len;
return offset;
}
*status_p = 0;
*status_p = 0;
- if (!strncmp(buffer, "delta ", 6)) {
+ if (!prefixcmp(buffer, "delta ")) {
patch_method = BINARY_DELTA_DEFLATED;
origlen = strtoul(buffer + 6, NULL, 10);
}
patch_method = BINARY_DELTA_DEFLATED;
origlen = strtoul(buffer + 6, NULL, 10);
}
- else if (!strncmp(buffer, "literal ", 8)) {
+ else if (!prefixcmp(buffer, "literal ")) {
patch_method = BINARY_LITERAL_DEFLATED;
origlen = strtoul(buffer + 8, NULL, 10);
}
patch_method = BINARY_LITERAL_DEFLATED;
origlen = strtoul(buffer + 8, NULL, 10);
}
free(qname);
}
free(qname);
}
-static int read_old_data(struct stat *st, const char *path, void *buf, unsigned long size)
+static int read_old_data(struct stat *st, const char *path, char **buf_p, unsigned long *alloc_p, unsigned long *size_p)
{
int fd;
unsigned long got;
{
int fd;
unsigned long got;
+ unsigned long nsize;
+ char *nbuf;
+ unsigned long size = *size_p;
+ char *buf = *buf_p;
switch (st->st_mode & S_IFMT) {
case S_IFLNK:
switch (st->st_mode & S_IFMT) {
case S_IFLNK:
- return readlink(path, buf, size);
+ return readlink(path, buf, size) != size;
case S_IFREG:
fd = open(path, O_RDONLY);
if (fd < 0)
return error("unable to open %s", path);
got = 0;
for (;;) {
case S_IFREG:
fd = open(path, O_RDONLY);
if (fd < 0)
return error("unable to open %s", path);
got = 0;
for (;;) {
- int ret = xread(fd, (char *) buf + got, size - got);
+ int ret = xread(fd, buf + got, size - got);
if (ret <= 0)
break;
got += ret;
}
close(fd);
if (ret <= 0)
break;
got += ret;
}
close(fd);
- return got;
-
+ nsize = got;
+ nbuf = buf;
+ if (convert_to_git(path, &nbuf, &nsize)) {
+ free(buf);
+ *buf_p = nbuf;
+ *alloc_p = nsize;
+ *size_p = nsize;
+ }
+ return got != size;
default:
return -1;
}
default:
return -1;
}
@@ -1910,7 +1978,7 @@ static int apply_data(struct patch *patch, struct stat *st, struct cache_entry *
size = st->st_size;
alloc = size + 8192;
buf = xmalloc(alloc);
size = st->st_size;
alloc = size + 8192;
buf = xmalloc(alloc);
- if (read_old_data(st, patch->old_name, buf, alloc) != size)
+ 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);
}
return error("%s: %s", old_name, strerror(errno));
if (!cached)
return error("%s: %s", old_name, strerror(errno));
if (!cached)
- st_mode = ntohl(create_ce_mode(st.st_mode));
+ st_mode = ntohl(ce_mode_from_stat(ce, st.st_mode));
if (patch->is_new < 0)
patch->is_new = 0;
if (patch->is_new < 0)
patch->is_new = 0;
}
}
}
}
-static void remove_file(struct patch *patch)
+static void remove_file(struct patch *patch, int rmdir_empty)
{
if (write_index) {
if (remove_file_from_cache(patch->old_name) < 0)
{
if (write_index) {
if (remove_file_from_cache(patch->old_name) < 0)
cache_tree_invalidate_path(active_cache_tree, patch->old_name);
}
if (!cached) {
cache_tree_invalidate_path(active_cache_tree, patch->old_name);
}
if (!cached) {
- if (!unlink(patch->old_name)) {
+ 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) {
@@ -2282,12 +2350,22 @@ static void add_index_file(const char *path, unsigned mode, void *buf, unsigned
static int try_create_file(const char *path, unsigned int mode, const char *buf, unsigned long size)
{
int fd;
static int try_create_file(const char *path, unsigned int mode, const char *buf, unsigned long size)
{
int fd;
+ char *nbuf;
+ unsigned long nsize;
if (S_ISLNK(mode))
/* Although buf:size is counted string, it also is NUL
* terminated.
*/
return symlink(buf, path);
if (S_ISLNK(mode))
/* Although buf:size is counted string, it also is NUL
* terminated.
*/
return symlink(buf, path);
+ nsize = size;
+ nbuf = (char *) buf;
+ if (convert_to_working_tree(path, &nbuf, &nsize)) {
+ free((char *) buf);
+ buf = nbuf;
+ size = nsize;
+ }
+
fd = open(path, O_CREAT | O_EXCL | O_WRONLY, (mode & 0100) ? 0777 : 0666);
if (fd < 0)
return -1;
fd = open(path, O_CREAT | O_EXCL | O_WRONLY, (mode & 0100) ? 0777 : 0666);
if (fd < 0)
return -1;
{
if (patch->is_delete > 0) {
if (phase == 0)
{
if (patch->is_delete > 0) {
if (phase == 0)
- remove_file(patch);
+ remove_file(patch, 1);
return;
}
if (patch->is_new > 0 || patch->is_copy) {
return;
}
if (patch->is_new > 0 || patch->is_copy) {
* thing: remove the old, write the new
*/
if (phase == 0)
* thing: remove the old, write the new
*/
if (phase == 0)
- remove_file(patch);
+ remove_file(patch, 0);
if (phase == 1)
create_file(patch);
}
if (phase == 1)
create_file(patch);
}
return 1;
}
return 1;
}
+static void prefix_one(char **name)
+{
+ char *old_name = *name;
+ if (!old_name)
+ return;
+ *name = xstrdup(prefix_filename(prefix, prefix_length, *name));
+ free(old_name);
+}
+
+static void prefix_patches(struct patch *p)
+{
+ if (!prefix || p->is_toplevel_relative)
+ return;
+ for ( ; p; p = p->next) {
+ if (p->new_name == p->old_name) {
+ char *prefixed = p->new_name;
+ prefix_one(&prefixed);
+ p->new_name = p->old_name = prefixed;
+ }
+ else {
+ prefix_one(&p->new_name);
+ prefix_one(&p->old_name);
+ }
+ }
+}
+
static int apply_patch(int fd, const char *filename, int inaccurate_eof)
{
unsigned long offset, size;
static int apply_patch(int fd, const char *filename, int inaccurate_eof)
{
unsigned long offset, size;
break;
if (apply_in_reverse)
reverse_patches(patch);
break;
if (apply_in_reverse)
reverse_patches(patch);
+ if (prefix)
+ prefix_patches(patch);
if (use_patch(patch)) {
patch_stats(patch);
*listp = patch;
listp = &patch->next;
if (use_patch(patch)) {
patch_stats(patch);
*listp = patch;
listp = &patch->next;
- } else {
+ }
+ else {
/* perhaps free it a bit better? */
free(patch);
skipped_patch++;
/* perhaps free it a bit better? */
free(patch);
skipped_patch++;
read_stdin = 0;
continue;
}
read_stdin = 0;
continue;
}
- if (!strncmp(arg, "--exclude=", 10)) {
+ if (!prefixcmp(arg, "--exclude=")) {
struct excludes *x = xmalloc(sizeof(*x));
x->path = arg + 10;
x->next = excludes;
excludes = x;
continue;
}
struct excludes *x = xmalloc(sizeof(*x));
x->path = arg + 10;
x->next = excludes;
excludes = x;
continue;
}
- if (!strncmp(arg, "-p", 2)) {
+ if (!prefixcmp(arg, "-p")) {
p_value = atoi(arg + 2);
p_value = atoi(arg + 2);
+ p_value_known = 1;
continue;
}
if (!strcmp(arg, "--no-add")) {
continue;
}
if (!strcmp(arg, "--no-add")) {
line_termination = 0;
continue;
}
line_termination = 0;
continue;
}
- if (!strncmp(arg, "-C", 2)) {
+ if (!prefixcmp(arg, "-C")) {
p_context = strtoul(arg + 2, &end, 0);
if (*end != '\0')
die("unrecognized context count '%s'", arg + 2);
continue;
}
p_context = strtoul(arg + 2, &end, 0);
if (*end != '\0')
die("unrecognized context count '%s'", arg + 2);
continue;
}
- if (!strncmp(arg, "--whitespace=", 13)) {
+ if (!prefixcmp(arg, "--whitespace=")) {
whitespace_option = arg + 13;
parse_whitespace_option(arg + 13);
continue;
whitespace_option = arg + 13;
parse_whitespace_option(arg + 13);
continue;