X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;f=builtin-apply.c;h=86d89a4a7e9240a75e1500bba524acdcec7f14d2;hb=e4cd6c7a20bfc776086817671d58e09060a8079a;hp=e71789803749b22a3ec041b2bce533957cea1c72;hpb=1654a3ba0c3a91ee3c0f38c922e3d2d1255ec868;p=git.git diff --git a/builtin-apply.c b/builtin-apply.c index e71789803..86d89a4a7 100644 --- a/builtin-apply.c +++ b/builtin-apply.c @@ -55,7 +55,7 @@ static enum whitespace_eol { } 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) @@ -254,7 +254,7 @@ static char *find_name(const char *line, char *def, int p_value, int terminate) if (name) { char *cp = name; while (p_value) { - cp = strchr(name, '/'); + cp = strchr(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 '-': + if (apply_in_reverse && + new_whitespace != nowarn_whitespace) + check_whitespace(line, len); 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--; @@ -1510,7 +1514,8 @@ static int find_offset(const char *buf, unsigned long size, const char *fragment } /* Exact line number? */ - if (!memcmp(buf + start, fragment, fragsize)) + if ((start + fragsize <= size) && + !memcmp(buf + start, fragment, fragsize)) return start; /* @@ -1637,15 +1642,22 @@ static int apply_line(char *output, const char *patch, int plen) 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]; - if (ch != ' ') + if (ch != ' ') { + consecutive_spaces = 0; *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; @@ -1657,7 +1669,7 @@ static int apply_line(char *output, const char *patch, int plen) if (add_nl_to_tail) output[plen++] = '\n'; if (fixed) - applied_after_stripping++; + applied_after_fixing_ws++; return output + plen - buf; } @@ -1980,6 +1992,25 @@ static int apply_fragments(struct buffer_desc *desc, struct patch *patch) 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; @@ -1990,22 +2021,32 @@ static int apply_data(struct patch *patch, struct stat *st, struct cache_entry * 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); - 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; @@ -2051,6 +2092,16 @@ static int check_to_create_blob(const char *new_name, int ok_if_exists) 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; @@ -2061,8 +2112,14 @@ static int check_patch(struct patch *patch, struct patch *prev_patch) 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) { - int changed = 0; int stat_ret = 0; unsigned st_mode = 0; @@ -2092,15 +2149,12 @@ static int check_patch(struct patch *patch, struct patch *prev_patch) 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); - } - else if (stat_ret < 0) + } else if (stat_ret < 0) return error("%s: %s", old_name, strerror(errno)); if (!cached) @@ -2180,6 +2234,20 @@ static int check_patch_list(struct patch *patch) 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; @@ -2196,8 +2264,16 @@ static void show_index_list(struct patch *list) 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; @@ -2347,10 +2423,13 @@ static void remove_file(struct patch *patch, int rmdir_empty) 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 (!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) { @@ -2378,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); - 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); } @@ -2394,6 +2481,13 @@ static int try_create_file(const char *path, unsigned int mode, const char *buf, 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. @@ -2483,7 +2577,6 @@ static void create_file(struct patch *patch) 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 */ @@ -2504,7 +2597,7 @@ static void write_out_one_result(struct patch *patch, int phase) * 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); } @@ -2884,18 +2977,17 @@ int cmd_apply(int argc, const char **argv, const char *unused_prefix) 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" : ""); - if (applied_after_stripping) + if (applied_after_fixing_ws) 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) - 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" : "");