vendor/libgit2/src/patch_parse.c in rugged-0.28.4 vs vendor/libgit2/src/patch_parse.c in rugged-0.28.4.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,55 +56,44 @@ 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); @@ -129,18 +106,13 @@ 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); return error; @@ -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); } @@ -403,11 +375,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 +392,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 +459,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; @@ -552,48 +522,33 @@ git_error_set(GIT_ERROR_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 +576,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); 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; @@ -763,11 +685,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 +728,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( @@ -876,27 +798,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; @@ -1125,22 +1036,18 @@ } 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);