From: Junio C Hamano Date: Wed, 28 Feb 2018 21:37:55 +0000 (-0800) Subject: Merge branch 'tk/apply-dev-null-verify-name-fix' X-Git-Tag: v2.17.0-rc0~56 X-Git-Url: https://git.lorimer.id.au/gitweb.git/diff_plain/177bd65cf8601216e906ad56ceb6a46f57df22fa?ds=inline;hp=-c Merge branch 'tk/apply-dev-null-verify-name-fix' Many places in "git apply" knew that "/dev/null" that signals "there is no such file on this side of the diff" can be followed by whitespace and garbage when parsing a patch, except for one, which made an otherwise valid patch (e.g. ones from subversion) rejected. * tk/apply-dev-null-verify-name-fix: apply: handle Subversion diffs with /dev/null gracefully apply: demonstrate a problem applying svn diffs --- 177bd65cf8601216e906ad56ceb6a46f57df22fa diff --combined apply.c index 40a368b315,3aadbae305..7c88d4ee71 --- a/apply.c +++ b/apply.c @@@ -75,10 -75,13 +75,10 @@@ static int parse_ignorewhitespace_optio } int init_apply_state(struct apply_state *state, - const char *prefix, - struct lock_file *lock_file) + const char *prefix) { memset(state, 0, sizeof(*state)); state->prefix = prefix; - state->lock_file = lock_file; - state->newfd = -1; state->apply = 1; state->line_termination = '\n'; state->p_value = 1; @@@ -143,6 -146,8 +143,6 @@@ int check_apply_state(struct apply_stat } if (state->check_index) state->unsafe_paths = 0; - if (!state->lock_file) - return error("BUG: state->lock_file should not be NULL"); if (state->apply_verbosity <= verbosity_silent) { state->saved_error_routine = get_error_routine(); @@@ -300,33 -305,52 +300,33 @@@ static uint32_t hash_line(const char *c static int fuzzy_matchlines(const char *s1, size_t n1, const char *s2, size_t n2) { - const char *last1 = s1 + n1 - 1; - const char *last2 = s2 + n2 - 1; - int result = 0; + const char *end1 = s1 + n1; + const char *end2 = s2 + n2; /* ignore line endings */ - while ((*last1 == '\r') || (*last1 == '\n')) - last1--; - while ((*last2 == '\r') || (*last2 == '\n')) - last2--; - - /* skip leading whitespaces, if both begin with whitespace */ - if (s1 <= last1 && s2 <= last2 && isspace(*s1) && isspace(*s2)) { - while (isspace(*s1) && (s1 <= last1)) - s1++; - while (isspace(*s2) && (s2 <= last2)) - s2++; - } - /* early return if both lines are empty */ - if ((s1 > last1) && (s2 > last2)) - return 1; - while (!result) { - result = *s1++ - *s2++; - /* - * Skip whitespace inside. We check for whitespace on - * both buffers because we don't want "a b" to match - * "ab" - */ - if (isspace(*s1) && isspace(*s2)) { - while (isspace(*s1) && s1 <= last1) + while (s1 < end1 && (end1[-1] == '\r' || end1[-1] == '\n')) + end1--; + while (s2 < end2 && (end2[-1] == '\r' || end2[-1] == '\n')) + end2--; + + while (s1 < end1 && s2 < end2) { + if (isspace(*s1)) { + /* + * Skip whitespace. We check on both buffers + * because we don't want "a b" to match "ab". + */ + if (!isspace(*s2)) + return 0; + while (s1 < end1 && isspace(*s1)) s1++; - while (isspace(*s2) && s2 <= last2) + while (s2 < end2 && isspace(*s2)) s2++; - } - /* - * If we reached the end on one side only, - * lines don't match - */ - if ( - ((s2 > last2) && (s1 <= last1)) || - ((s1 > last1) && (s2 <= last2))) + } else if (*s1++ != *s2++) return 0; - if ((s1 > last1) && (s2 > last2)) - break; } - return !result; + /* If we reached the end on one side only, lines don't match. */ + return s1 == end1 && s2 == end2; } static void add_line_info(struct image *img, const char *bol, size_t len, unsigned flag) @@@ -788,13 -812,16 +788,13 @@@ static int has_epoch_timestamp(const ch * 1970-01-01, and the seconds part must be "00". */ const char stamp_regexp[] = - "^(1969-12-31|1970-01-01)" - " " - "[0-2][0-9]:[0-5][0-9]:00(\\.0+)?" + "^[0-2][0-9]:([0-5][0-9]):00(\\.0+)?" " " "([-+][0-2][0-9]:?[0-5][0-9])\n"; const char *timestamp = NULL, *cp, *colon; static regex_t *stamp; regmatch_t m[10]; - int zoneoffset; - int hourminute; + int zoneoffset, epoch_hour, hour, minute; int status; for (cp = nameline; *cp != '\n'; cp++) { @@@ -803,18 -830,6 +803,18 @@@ } if (!timestamp) return 0; + + /* + * YYYY-MM-DD hh:mm:ss must be from either 1969-12-31 + * (west of GMT) or 1970-01-01 (east of GMT) + */ + if (skip_prefix(timestamp, "1969-12-31 ", ×tamp)) + epoch_hour = 24; + else if (skip_prefix(timestamp, "1970-01-01 ", ×tamp)) + epoch_hour = 0; + else + return 0; + if (!stamp) { stamp = xmalloc(sizeof(*stamp)); if (regcomp(stamp, stamp_regexp, REG_EXTENDED)) { @@@ -832,9 -847,6 +832,9 @@@ return 0; } + hour = strtol(timestamp, NULL, 10); + minute = strtol(timestamp + m[1].rm_so, NULL, 10); + zoneoffset = strtol(timestamp + m[3].rm_so + 1, (char **) &colon, 10); if (*colon == ':') zoneoffset = zoneoffset * 60 + strtol(colon + 1, NULL, 10); @@@ -843,7 -855,20 +843,7 @@@ if (timestamp[m[3].rm_so] == '-') zoneoffset = -zoneoffset; - /* - * YYYY-MM-DD hh:mm:ss must be from either 1969-12-31 - * (west of GMT) or 1970-01-01 (east of GMT) - */ - if ((zoneoffset < 0 && memcmp(timestamp, "1969-12-31", 10)) || - (0 <= zoneoffset && memcmp(timestamp, "1970-01-01", 10))) - return 0; - - hourminute = (strtol(timestamp + 11, NULL, 10) * 60 + - strtol(timestamp + 14, NULL, 10) - - zoneoffset); - - return ((zoneoffset < 0 && hourminute == 1440) || - (0 <= zoneoffset && !hourminute)); + return hour * 60 + minute - zoneoffset == epoch_hour * 60; } /* @@@ -950,7 -975,7 +950,7 @@@ static int gitdiff_verify_name(struct a } free(another); } else { - if (!starts_with(line, "/dev/null\n")) + if (!is_dev_null(line)) return error(_("git apply: bad git-diff - expected /dev/null on line %d"), state->linenr); } @@@ -2263,8 -2288,8 +2263,8 @@@ static void show_stats(struct apply_sta static int read_old_data(struct stat *st, struct patch *patch, const char *path, struct strbuf *buf) { - enum safe_crlf safe_crlf = patch->crlf_in_old ? - SAFE_CRLF_KEEP_CRLF : SAFE_CRLF_RENORMALIZE; + int conv_flags = patch->crlf_in_old ? + CONV_EOL_KEEP_CRLF : CONV_EOL_RENORMALIZE; switch (st->st_mode & S_IFMT) { case S_IFLNK: if (strbuf_readlink(buf, path, st->st_size) < 0) @@@ -2281,7 -2306,7 +2281,7 @@@ * should never look at the index when explicit crlf option * is given. */ - convert_to_git(NULL, path, buf->buf, buf->len, buf, safe_crlf); + convert_to_git(NULL, path, buf->buf, buf->len, buf, conv_flags); return 0; default: return -1; @@@ -2896,7 -2921,6 +2896,7 @@@ static int apply_one_fragment(struct ap if (plen && (ws_rule & WS_BLANK_AT_EOF) && ws_blank_line(patch + 1, plen, ws_rule)) is_blank_context = 1; + /* fallthrough */ case '-': memcpy(old, patch + 1, plen); add_line_info(&preimage, old, plen, @@@ -2904,7 -2928,7 +2904,7 @@@ old += plen; if (first == '-') break; - /* Fall-through for ' ' */ + /* fallthrough */ case '+': /* --no-add does not add new lines */ if (first == '+' && state->no_add) @@@ -2953,8 -2977,6 +2953,8 @@@ newlines.len > 0 && newlines.buf[newlines.len - 1] == '\n') { old--; strbuf_setlen(&newlines, newlines.len - 1); + preimage.line_allocated[preimage.nr - 1].len--; + postimage.line_allocated[postimage.nr - 1].len--; } leading = frag->leading; @@@ -3154,7 -3176,7 +3154,7 @@@ static int apply_binary(struct apply_st * See if the old one matches what the patch * applies to. */ - hash_sha1_file(img->buf, img->len, blob_type, oid.hash); + hash_object_file(img->buf, img->len, blob_type, &oid); if (strcmp(oid_to_hex(&oid), patch->old_sha1_prefix)) return error(_("the patch applies to '%s' (%s), " "which does not match the " @@@ -3199,7 -3221,7 +3199,7 @@@ name); /* verify that the result matches */ - hash_sha1_file(img->buf, img->len, blob_type, oid.hash); + hash_object_file(img->buf, img->len, blob_type, &oid); if (strcmp(oid_to_hex(&oid), patch->new_sha1_prefix)) return error(_("binary patch to '%s' creates incorrect result (expecting %s, got %s)"), name, patch->new_sha1_prefix, oid_to_hex(&oid)); @@@ -3554,8 -3576,8 +3554,8 @@@ static int try_threeway(struct apply_st /* Preimage the patch was prepared for */ if (patch->is_new) - write_sha1_file("", 0, blob_type, pre_oid.hash); - else if (get_sha1(patch->old_sha1_prefix, pre_oid.hash) || + write_object_file("", 0, blob_type, &pre_oid); + else if (get_oid(patch->old_sha1_prefix, &pre_oid) || read_blob_object(&buf, &pre_oid, patch->old_mode)) return error(_("repository lacks the necessary blob to fall back on 3-way merge.")); @@@ -3570,7 -3592,7 +3570,7 @@@ return -1; } /* post_oid is theirs */ - write_sha1_file(tmp_image.buf, tmp_image.len, blob_type, post_oid.hash); + write_object_file(tmp_image.buf, tmp_image.len, blob_type, &post_oid); clear_image(&tmp_image); /* our_oid is ours */ @@@ -3583,7 -3605,7 +3583,7 @@@ return error(_("cannot read the current contents of '%s'"), patch->old_name); } - write_sha1_file(tmp_image.buf, tmp_image.len, blob_type, our_oid.hash); + write_object_file(tmp_image.buf, tmp_image.len, blob_type, &our_oid); clear_image(&tmp_image); /* in-core three-way merge between post and our using pre as base */ @@@ -4079,7 -4101,7 +4079,7 @@@ static int build_fake_ancestor(struct a else return error(_("sha1 information is lacking or " "useless for submodule %s"), name); - } else if (!get_sha1_blob(patch->old_sha1_prefix, oid.hash)) { + } else if (!get_oid_blob(patch->old_sha1_prefix, &oid)) { ; /* ok */ } else if (!patch->lines_added && !patch->lines_deleted) { /* mode-only change: update the current */ @@@ -4291,7 -4313,7 +4291,7 @@@ static int add_index_file(struct apply_ } fill_stat_cache_info(ce, &st); } - if (write_sha1_file(buf, size, blob_type, ce->oid.hash) < 0) { + if (write_object_file(buf, size, blob_type, &ce->oid) < 0) { free(ce); return error(_("unable to create backing store " "for newly created file %s"), path); @@@ -4687,13 -4709,13 +4687,13 @@@ static int apply_patch(struct apply_sta state->apply = 0; state->update_index = state->check_index && state->apply; - if (state->update_index && state->newfd < 0) { + if (state->update_index && !is_lock_file_locked(&state->lock_file)) { if (state->index_file) - state->newfd = hold_lock_file_for_update(state->lock_file, - state->index_file, - LOCK_DIE_ON_ERROR); + hold_lock_file_for_update(&state->lock_file, + state->index_file, + LOCK_DIE_ON_ERROR); else - state->newfd = hold_locked_index(state->lock_file, LOCK_DIE_ON_ERROR); + hold_locked_index(&state->lock_file, LOCK_DIE_ON_ERROR); } if (state->check_index && read_apply_cache(state) < 0) { @@@ -4889,18 -4911,22 +4889,18 @@@ int apply_all_patches(struct apply_stat } if (state->update_index) { - res = write_locked_index(&the_index, state->lock_file, COMMIT_LOCK); + res = write_locked_index(&the_index, &state->lock_file, COMMIT_LOCK); if (res) { error(_("Unable to write new index file")); res = -128; goto end; } - state->newfd = -1; } res = !!errs; end: - if (state->newfd >= 0) { - rollback_lock_file(state->lock_file); - state->newfd = -1; - } + rollback_lock_file(&state->lock_file); if (state->apply_verbosity <= verbosity_silent) { set_error_routine(state->saved_error_routine);