X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;f=builtin-apply.c;h=d924ac3d0ab663c2ceb05c2cb9943f6caa23c0ef;hb=56ac168f6f89bebf2846c4bafed01318fe3f25cd;hp=6a4fb9663dbfac93a7c625c13d401f411e8f5178;hpb=5ff6a3269085c5cd425bad9f470d421a8d62f338;p=git.git diff --git a/builtin-apply.c b/builtin-apply.c index 6a4fb9663..d924ac3d0 100644 --- a/builtin-apply.c +++ b/builtin-apply.c @@ -14,14 +14,15 @@ #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; @@ -125,6 +126,7 @@ struct patch { unsigned long deflate_origlen; int lines_added, lines_deleted; int score; + int inaccurate_eof:1; struct fragment *fragments; char *result; unsigned long resultsize; @@ -148,7 +150,7 @@ static void *read_patch_file(int fd, unsigned long *sizep) 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) @@ -164,7 +166,7 @@ static void *read_patch_file(int fd, unsigned long *sizep) */ if (alloc < size + SLOP) buffer = xrealloc(buffer, size + SLOP); - memset(buffer + size, 0, SLOP); + memset((char *) buffer + size, 0, SLOP); return buffer; } @@ -283,8 +285,8 @@ static void parse_traditional_patch(const char *first, const char *second, struc { 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; @@ -764,7 +766,7 @@ static int find_header(char *line, unsigned long size, int *hdrsize, struct patc 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. */ @@ -989,7 +991,7 @@ static int parse_binary(char *buffer, unsigned long size, struct patch *patch) * 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; @@ -1194,7 +1196,7 @@ static int read_old_data(struct stat *st, const char *path, void *buf, unsigned 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; @@ -1333,7 +1335,8 @@ static int apply_line(char *output, const char *patch, int plen) 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; @@ -1386,13 +1389,11 @@ static int apply_one_fragment(struct buffer_desc *desc, struct fragment *frag) 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; @@ -1614,7 +1615,7 @@ static int apply_fragments(struct buffer_desc *desc, struct patch *patch) 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; @@ -1663,13 +1664,14 @@ static int apply_data(struct patch *patch, struct stat *st, struct cache_entry * 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; @@ -1727,13 +1729,33 @@ static int check_patch(struct patch *patch) 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) { @@ -1761,10 +1783,13 @@ static int check_patch(struct patch *patch) 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; } @@ -2009,6 +2034,16 @@ static void create_one_file(char *path, unsigned mode, const char *buf, unsigned 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(); @@ -2043,36 +2078,46 @@ static void create_file(struct patch *patch) 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; @@ -2097,7 +2142,7 @@ static int use_patch(struct patch *p) 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); @@ -2113,6 +2158,7 @@ static int apply_patch(int fd, const char *filename) int nr; patch = xcalloc(1, sizeof(*patch)); + patch->inaccurate_eof = inaccurate_eof; nr = parse_chunk(buffer + offset, size, patch); if (nr < 0) break; @@ -2133,8 +2179,12 @@ static int apply_patch(int fd, const char *filename) 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"); @@ -2176,6 +2226,8 @@ int cmd_apply(int argc, const char **argv, char **envp) { int i; int read_stdin = 1; + int inaccurate_eof = 0; + const char *whitespace_option = NULL; for (i = 1; i < argc; i++) { @@ -2184,7 +2236,7 @@ int cmd_apply(int argc, const char **argv, char **envp) int fd; if (!strcmp(arg, "-")) { - apply_patch(0, ""); + apply_patch(0, "", inaccurate_eof); read_stdin = 0; continue; } @@ -2261,6 +2313,10 @@ int cmd_apply(int argc, const char **argv, char **envp) 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(); @@ -2277,12 +2333,12 @@ int cmd_apply(int argc, const char **argv, char **envp) 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, ""); + apply_patch(0, "", inaccurate_eof); if (whitespace_error) { if (squelch_whitespace_errors && squelch_whitespace_errors < whitespace_error) { @@ -2312,8 +2368,8 @@ int cmd_apply(int argc, const char **argv, char **envp) 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;