vendor/libgit2/src/patch_parse.c in rugged-0.27.10 vs vendor/libgit2/src/patch_parse.c in rugged-0.27.10.1

- old
+ new

@@ -31,24 +31,12 @@ /* the prefixes from the old/new paths */ char *old_prefix, *new_prefix; } git_patch_parsed; -static int git_parse_err(const char *fmt, ...) GIT_FORMAT_PRINTF(1, 2); -static int git_parse_err(const char *fmt, ...) +static int header_path_len(git_patch_parse_ctx *ctx) { - va_list ap; - - va_start(ap, fmt); - git_error_vset(GIT_ERROR_PATCH, fmt, ap); - va_end(ap); - - return -1; -} - -static size_t header_path_len(git_patch_parse_ctx *ctx) -{ bool inquote = 0; bool quoted = git_parse_ctx_contains_s(&ctx->parse_ctx, "\""); size_t len; for (len = quoted; len < ctx->parse_ctx.line_len; len++) { @@ -68,83 +56,67 @@ static int parse_header_path_buf(git_buf *path, git_patch_parse_ctx *ctx, size_t path_len) { int error; if ((error = git_buf_put(path, ctx->parse_ctx.line, path_len)) < 0) - return error; + goto done; git_parse_advance_chars(&ctx->parse_ctx, path_len); git_buf_rtrim(path); - if (path->size > 0 && path->ptr[0] == '"' && - (error = git_buf_unquote(path)) < 0) - return error; + if (path->size > 0 && path->ptr[0] == '"') + error = git_buf_unquote(path); + if (error < 0) + goto done; + git_path_squash_slashes(path); - if (!path->size) - return git_parse_err("patch contains empty path at line %"PRIuZ, - ctx->parse_ctx.line_num); - - return 0; +done: + return error; } static int parse_header_path(char **out, git_patch_parse_ctx *ctx) { git_buf path = GIT_BUF_INIT; - int error; + int error = parse_header_path_buf(&path, ctx, header_path_len(ctx)); - if ((error = parse_header_path_buf(&path, ctx, header_path_len(ctx))) < 0) - goto out; *out = git_buf_detach(&path); -out: - git_buf_dispose(&path); return error; } static int parse_header_git_oldpath( git_patch_parsed *patch, git_patch_parse_ctx *ctx) { git_buf old_path = GIT_BUF_INIT; int error; - if (patch->old_path) { - error = git_parse_err("patch contains duplicate old path at line %"PRIuZ, - ctx->parse_ctx.line_num); - goto out; - } - if ((error = parse_header_path_buf(&old_path, ctx, ctx->parse_ctx.line_len - 1)) < 0) goto out; patch->old_path = git_buf_detach(&old_path); out: - git_buf_dispose(&old_path); + git_buf_free(&old_path); return error; } static int parse_header_git_newpath( git_patch_parsed *patch, git_patch_parse_ctx *ctx) { git_buf new_path = GIT_BUF_INIT; int error; - if (patch->new_path) { - error = git_parse_err("patch contains duplicate new path at line %"PRIuZ, - ctx->parse_ctx.line_num); - goto out; - } - if ((error = parse_header_path_buf(&new_path, ctx, ctx->parse_ctx.line_len - 1)) < 0) goto out; + patch->new_path = git_buf_detach(&new_path); out: - git_buf_dispose(&new_path); + git_buf_free(&new_path); return error; } static int parse_header_mode(uint16_t *mode, git_patch_parse_ctx *ctx) { @@ -229,26 +201,26 @@ static int parse_header_git_deletedfilemode( git_patch_parsed *patch, git_patch_parse_ctx *ctx) { - git__free((char *)patch->base.delta->new_file.path); + git__free((char *)patch->base.delta->old_file.path); - patch->base.delta->new_file.path = NULL; + patch->base.delta->old_file.path = NULL; patch->base.delta->status = GIT_DELTA_DELETED; patch->base.delta->nfiles = 1; return parse_header_mode(&patch->base.delta->old_file.mode, ctx); } static int parse_header_git_newfilemode( git_patch_parsed *patch, git_patch_parse_ctx *ctx) { - git__free((char *)patch->base.delta->old_file.path); + git__free((char *)patch->base.delta->new_file.path); - patch->base.delta->old_file.path = NULL; + patch->base.delta->new_file.path = NULL; patch->base.delta->status = GIT_DELTA_ADDED; patch->base.delta->nfiles = 1; return parse_header_mode(&patch->base.delta->new_file.mode, ctx); } @@ -308,11 +280,11 @@ return -1; if (val < 0 || val > 100) return -1; - *out = (uint16_t)val; + *out = val; return 0; } static int parse_header_similarity( git_patch_parsed *patch, git_patch_parse_ctx *ctx) @@ -354,12 +326,11 @@ * point. Due to the possibility of unquoted names, whitespaces in * filenames and custom prefixes we have to allow that, though, and just * proceeed here. We then hope for the "---" and "+++" lines to fix that * for us. */ - if (!git_parse_ctx_contains(&ctx->parse_ctx, "\n", 1) && - !git_parse_ctx_contains(&ctx->parse_ctx, "\r\n", 2)) { + if (!git_parse_ctx_contains(&ctx->parse_ctx, "\n", 1)) { git_parse_advance_chars(&ctx->parse_ctx, ctx->parse_ctx.line_len - 1); git__free(patch->header_old_path); patch->header_old_path = NULL; git__free(patch->header_new_path); @@ -403,11 +374,10 @@ { "index " , STATE_FILEMODE, STATE_INDEX, parse_header_git_index }, { "index " , STATE_DIFF, STATE_INDEX, parse_header_git_index }, { "index " , STATE_END, STATE_INDEX, parse_header_git_index }, - { "--- " , STATE_DIFF, STATE_PATH, parse_header_git_oldpath }, { "--- " , STATE_INDEX, STATE_PATH, parse_header_git_oldpath }, { "+++ " , STATE_PATH, STATE_END, parse_header_git_newpath }, { "GIT binary patch" , STATE_INDEX, STATE_END, NULL }, { "Binary files " , STATE_INDEX, STATE_END, NULL }, @@ -421,11 +391,10 @@ { "copy to " , STATE_COPY, STATE_END, parse_header_copyto }, /* Next patch */ { "diff --git " , STATE_END, 0, NULL }, { "@@ -" , STATE_END, 0, NULL }, - { "-- " , STATE_INDEX, 0, NULL }, { "-- " , STATE_END, 0, NULL }, }; static int parse_header_git( git_patch_parsed *patch, @@ -489,11 +458,11 @@ return error; } static int parse_int(int *out, git_patch_parse_ctx *ctx) { - int64_t num; + git_off_t num; if (git_parse_advance_digit(&num, &ctx->parse_ctx, 10) < 0 || !git__is_int(num)) return -1; *out = (int)num; @@ -547,53 +516,38 @@ hunk->hunk.header[hunk->hunk.header_len] = '\0'; return 0; fail: - git_error_set(GIT_ERROR_PATCH, "invalid patch hunk header at line %"PRIuZ, + giterr_set(GITERR_PATCH, "invalid patch hunk header at line %"PRIuZ, ctx->parse_ctx.line_num); return -1; } -static int eof_for_origin(int origin) { - if (origin == GIT_DIFF_LINE_ADDITION) - return GIT_DIFF_LINE_ADD_EOFNL; - if (origin == GIT_DIFF_LINE_DELETION) - return GIT_DIFF_LINE_DEL_EOFNL; - return GIT_DIFF_LINE_CONTEXT_EOFNL; -} - static int parse_hunk_body( git_patch_parsed *patch, git_patch_hunk *hunk, git_patch_parse_ctx *ctx) { git_diff_line *line; int error = 0; int oldlines = hunk->hunk.old_lines; int newlines = hunk->hunk.new_lines; - int last_origin = 0; for (; ctx->parse_ctx.remain_len > 1 && (oldlines || newlines) && !git_parse_ctx_contains_s(&ctx->parse_ctx, "@@ -"); git_parse_advance_line(&ctx->parse_ctx)) { - int old_lineno, new_lineno, origin, prefix = 1; char c; + int origin; + int prefix = 1; + int old_lineno = hunk->hunk.old_start + (hunk->hunk.old_lines - oldlines); + int new_lineno = hunk->hunk.new_start + (hunk->hunk.new_lines - newlines); - if (git__add_int_overflow(&old_lineno, hunk->hunk.old_start, hunk->hunk.old_lines) || - git__sub_int_overflow(&old_lineno, old_lineno, oldlines) || - git__add_int_overflow(&new_lineno, hunk->hunk.new_start, hunk->hunk.new_lines) || - git__sub_int_overflow(&new_lineno, new_lineno, newlines)) { - error = git_parse_err("unrepresentable line count at line %"PRIuZ, - ctx->parse_ctx.line_num); - goto done; - } - if (ctx->parse_ctx.line_len == 0 || ctx->parse_ctx.line[ctx->parse_ctx.line_len - 1] != '\n') { error = git_parse_err("invalid patch instruction at line %"PRIuZ, ctx->parse_ctx.line_num); goto done; } @@ -621,88 +575,55 @@ origin = GIT_DIFF_LINE_ADDITION; newlines--; old_lineno = -1; break; - case '\\': - /* - * If there are no oldlines left, then this is probably - * the "\ No newline at end of file" marker. Do not - * verify its format, as it may be localized. - */ - if (!oldlines) { - prefix = 0; - origin = eof_for_origin(last_origin); - old_lineno = -1; - new_lineno = -1; - break; - } - /* fall through */ - default: error = git_parse_err("invalid patch hunk at line %"PRIuZ, ctx->parse_ctx.line_num); goto done; } line = git_array_alloc(patch->base.lines); - GIT_ERROR_CHECK_ALLOC(line); + GITERR_CHECK_ALLOC(line); memset(line, 0x0, sizeof(git_diff_line)); + line->content = ctx->parse_ctx.line + prefix; line->content_len = ctx->parse_ctx.line_len - prefix; - line->content = git__strndup(ctx->parse_ctx.line + prefix, line->content_len); - GIT_ERROR_CHECK_ALLOC(line->content); line->content_offset = ctx->parse_ctx.content_len - ctx->parse_ctx.remain_len; line->origin = origin; line->num_lines = 1; line->old_lineno = old_lineno; line->new_lineno = new_lineno; hunk->line_count++; - - last_origin = origin; } if (oldlines || newlines) { error = git_parse_err( "invalid patch hunk, expected %d old lines and %d new lines", hunk->hunk.old_lines, hunk->hunk.new_lines); goto done; } - /* - * Handle "\ No newline at end of file". Only expect the leading + /* Handle "\ No newline at end of file". Only expect the leading * backslash, though, because the rest of the string could be * localized. Because `diff` optimizes for the case where you * want to apply the patch by hand. */ if (git_parse_ctx_contains_s(&ctx->parse_ctx, "\\ ") && git_array_size(patch->base.lines) > 0) { line = git_array_get(patch->base.lines, git_array_size(patch->base.lines) - 1); if (line->content_len < 1) { - error = git_parse_err("last line has no trailing newline"); + error = git_parse_err("cannot trim trailing newline of empty line"); goto done; } - line = git_array_alloc(patch->base.lines); - GIT_ERROR_CHECK_ALLOC(line); + line->content_len--; - memset(line, 0x0, sizeof(git_diff_line)); - - line->content_len = ctx->parse_ctx.line_len; - line->content = git__strndup(ctx->parse_ctx.line, line->content_len); - GIT_ERROR_CHECK_ALLOC(line->content); - line->content_offset = ctx->parse_ctx.content_len - ctx->parse_ctx.remain_len; - line->origin = eof_for_origin(last_origin); - line->num_lines = 1; - line->old_lineno = -1; - line->new_lineno = -1; - - hunk->line_count++; - git_parse_advance_line(&ctx->parse_ctx); } done: return error; @@ -727,11 +648,11 @@ /* If this cannot be parsed as a hunk header, it's just leading * noise, continue. */ if (parse_hunk_header(&hunk, ctx) < 0) { - git_error_clear(); + giterr_clear(); continue; } error = git_parse_err("invalid hunk header outside patch at line %"PRIuZ, line_num); @@ -750,11 +671,11 @@ error = 0; continue; } - git_error_set(GIT_ERROR_PATCH, "no patch found"); + giterr_set(GITERR_PATCH, "no patch found"); error = GIT_ENOTFOUND; done: return error; } @@ -763,11 +684,11 @@ git_diff_binary_file *binary, git_patch_parse_ctx *ctx) { git_diff_binary_t type = GIT_DIFF_BINARY_NONE; git_buf base85 = GIT_BUF_INIT, decoded = GIT_BUF_INIT; - int64_t len; + git_off_t len; int error = 0; if (git_parse_ctx_contains_s(&ctx->parse_ctx, "literal ")) { type = GIT_DIFF_BINARY_LITERAL; git_parse_advance_chars(&ctx->parse_ctx, 8); @@ -806,11 +727,11 @@ git_parse_advance_chars(&ctx->parse_ctx, 1); encoded_len = ((decoded_len / 4) + !!(decoded_len % 4)) * 5; - if (!encoded_len || !ctx->parse_ctx.line_len || encoded_len > ctx->parse_ctx.line_len - 1) { + if (encoded_len > ctx->parse_ctx.line_len - 1) { error = git_parse_err("truncated binary data at line %"PRIuZ, ctx->parse_ctx.line_num); goto done; } if ((error = git_buf_decode_base85( @@ -834,12 +755,12 @@ binary->inflatedlen = (size_t)len; binary->datalen = decoded.size; binary->data = git_buf_detach(&decoded); done: - git_buf_dispose(&base85); - git_buf_dispose(&decoded); + git_buf_free(&base85); + git_buf_free(&decoded); return error; } static int parse_patch_binary( git_patch_parsed *patch, @@ -876,27 +797,16 @@ static int parse_patch_binary_nodata( git_patch_parsed *patch, git_patch_parse_ctx *ctx) { - const char *old = patch->old_path ? patch->old_path : patch->header_old_path; - const char *new = patch->new_path ? patch->new_path : patch->header_new_path; - - if (!old || !new) - return git_parse_err("corrupt binary data without paths at line %"PRIuZ, ctx->parse_ctx.line_num); - - if (patch->base.delta->status == GIT_DELTA_ADDED) - old = "/dev/null"; - else if (patch->base.delta->status == GIT_DELTA_DELETED) - new = "/dev/null"; - if (git_parse_advance_expected_str(&ctx->parse_ctx, "Binary files ") < 0 || - git_parse_advance_expected_str(&ctx->parse_ctx, old) < 0 || - git_parse_advance_expected_str(&ctx->parse_ctx, " and ") < 0 || - git_parse_advance_expected_str(&ctx->parse_ctx, new) < 0 || - git_parse_advance_expected_str(&ctx->parse_ctx, " differ") < 0 || - git_parse_advance_nl(&ctx->parse_ctx) < 0) + git_parse_advance_expected_str(&ctx->parse_ctx, patch->header_old_path) < 0 || + git_parse_advance_expected_str(&ctx->parse_ctx, " and ") < 0 || + git_parse_advance_expected_str(&ctx->parse_ctx, patch->header_new_path) < 0 || + git_parse_advance_expected_str(&ctx->parse_ctx, " differ") < 0 || + git_parse_advance_nl(&ctx->parse_ctx) < 0) return git_parse_err("corrupt git binary header at line %"PRIuZ, ctx->parse_ctx.line_num); patch->base.binary.contains_data = 0; patch->base.delta->flags |= GIT_DIFF_FLAG_BINARY; return 0; @@ -909,11 +819,11 @@ git_patch_hunk *hunk; int error = 0; while (git_parse_ctx_contains_s(&ctx->parse_ctx, "@@ -")) { hunk = git_array_alloc(patch->base.hunks); - GIT_ERROR_CHECK_ALLOC(hunk); + GITERR_CHECK_ALLOC(hunk); memset(hunk, 0, sizeof(git_patch_hunk)); hunk->line_start = git_array_size(patch->base.lines); hunk->line_count = 0; @@ -1009,19 +919,25 @@ if (!patch->old_path && patch->new_path) return git_parse_err("missing old path"); /* Ensure (non-renamed) paths match */ - if (check_header_names(patch->header_old_path, patch->old_path, "old", added) < 0 || - check_header_names(patch->header_new_path, patch->new_path, "new", deleted) < 0) + if (check_header_names( + patch->header_old_path, patch->old_path, "old", added) < 0 || + check_header_names( + patch->header_new_path, patch->new_path, "new", deleted) < 0) return -1; - prefixed_old = (!added && patch->old_path) ? patch->old_path : patch->header_old_path; - prefixed_new = (!deleted && patch->new_path) ? patch->new_path : patch->header_new_path; + prefixed_old = (!added && patch->old_path) ? patch->old_path : + patch->header_old_path; + prefixed_new = (!deleted && patch->new_path) ? patch->new_path : + patch->header_new_path; - if ((prefixed_old && check_prefix(&patch->old_prefix, &old_prefixlen, patch, prefixed_old) < 0) || - (prefixed_new && check_prefix(&patch->new_prefix, &new_prefixlen, patch, prefixed_new) < 0)) + if (check_prefix( + &patch->old_prefix, &old_prefixlen, patch, prefixed_old) < 0 || + check_prefix( + &patch->new_prefix, &new_prefixlen, patch, prefixed_new) < 0) return -1; /* Prefer the rename filenames as they are unambiguous and unprefixed */ if (patch->rename_old_path) patch->base.delta->old_file.path = patch->rename_old_path; @@ -1032,11 +948,11 @@ patch->base.delta->new_file.path = patch->rename_new_path; else patch->base.delta->new_file.path = prefixed_new + new_prefixlen; if (!patch->base.delta->old_file.path && - !patch->base.delta->new_file.path) + !patch->base.delta->new_file.path) return git_parse_err("git diff header lacks old / new paths"); return 0; } @@ -1046,18 +962,18 @@ if (check_filenames(patch) < 0) return -1; if (delta->old_file.path && - delta->status != GIT_DELTA_DELETED && - !delta->new_file.mode) + delta->status != GIT_DELTA_DELETED && + !delta->new_file.mode) delta->new_file.mode = delta->old_file.mode; if (delta->status == GIT_DELTA_MODIFIED && - !(delta->flags & GIT_DIFF_FLAG_BINARY) && - delta->new_file.mode == delta->old_file.mode && - git_array_size(patch->base.hunks) == 0) + !(delta->flags & GIT_DIFF_FLAG_BINARY) && + delta->new_file.mode == delta->old_file.mode && + git_array_size(patch->base.hunks) == 0) return git_parse_err("patch with no hunks"); if (delta->status == GIT_DELTA_ADDED) { memset(&delta->old_file.id, 0x0, sizeof(git_oid)); delta->old_file.id_abbrev = 0; @@ -1125,23 +1041,19 @@ } static void patch_parsed__free(git_patch *p) { git_patch_parsed *patch = (git_patch_parsed *)p; - git_diff_line *line; - size_t i; if (!patch) return; git_patch_parse_ctx_free(patch->ctx); git__free((char *)patch->base.binary.old_file.data); git__free((char *)patch->base.binary.new_file.data); git_array_clear(patch->base.hunks); - git_array_foreach(patch->base.lines, i, line) - git__free((char *) line->content); git_array_clear(patch->base.lines); git__free(patch->base.delta); git__free(patch->old_prefix); git__free(patch->new_prefix); @@ -1165,19 +1077,19 @@ assert(out && ctx); *out = NULL; patch = git__calloc(1, sizeof(git_patch_parsed)); - GIT_ERROR_CHECK_ALLOC(patch); + GITERR_CHECK_ALLOC(patch); patch->ctx = ctx; GIT_REFCOUNT_INC(patch->ctx); patch->base.free_fn = patch_parsed__free; patch->base.delta = git__calloc(1, sizeof(git_diff_delta)); - GIT_ERROR_CHECK_ALLOC(patch->base.delta); + GITERR_CHECK_ALLOC(patch->base.delta); patch->base.delta->status = GIT_DELTA_MODIFIED; patch->base.delta->nfiles = 2; start = ctx->parse_ctx.remain_len; @@ -1212,10 +1124,10 @@ { git_patch_parse_ctx *ctx; int error; ctx = git_patch_parse_ctx_init(content, content_len, opts); - GIT_ERROR_CHECK_ALLOC(ctx); + GITERR_CHECK_ALLOC(ctx); error = git_patch_parse(out, ctx); git_patch_parse_ctx_free(ctx); return error;