diff --git a/include/git2/diff.h b/include/git2/diff.h index f3bb337b7..065a786e9 100644 --- a/include/git2/diff.h +++ b/include/git2/diff.h @@ -264,10 +264,15 @@ typedef enum { * link, a submodule commit id, or even a tree (although that only if you * are tracking type changes or ignored/untracked directories). * - * The `oid` is the `git_oid` of the item. If the entry represents an + * The `id` is the `git_oid` of the item. If the entry represents an * absent side of a diff (e.g. the `old_file` of a `GIT_DELTA_ADDED` delta), * then the oid will be zeroes. * + * The `id_abbrev` represents the known length of the `id` field, when + * converted to a hex string. It is generally `GIT_OID_HEXSZ`, unless this + * delta was created from reading a patch file, in which case it may be + * abbreviated to something reasonable, like 7 characters. + * * `path` is the NUL-terminated path to the entry relative to the working * directory of the repository. * @@ -280,6 +285,7 @@ typedef enum { */ typedef struct { git_oid id; + int id_abbrev; const char *path; git_off_t size; uint32_t flags; diff --git a/src/diff.c b/src/diff.c index 26c0b895b..9c27511f6 100644 --- a/src/diff.c +++ b/src/diff.c @@ -151,11 +151,13 @@ static int diff_delta__from_one( delta->old_file.size = entry->file_size; delta->old_file.flags |= GIT_DIFF_FLAG_EXISTS; git_oid_cpy(&delta->old_file.id, &entry->id); + delta->old_file.id_abbrev = GIT_OID_HEXSZ; } else /* ADDED, IGNORED, UNTRACKED */ { delta->new_file.mode = entry->mode; delta->new_file.size = entry->file_size; delta->new_file.flags |= GIT_DIFF_FLAG_EXISTS; git_oid_cpy(&delta->new_file.id, &entry->id); + delta->new_file.id_abbrev = GIT_OID_HEXSZ; } delta->old_file.flags |= GIT_DIFF_FLAG_VALID_ID; @@ -208,12 +210,14 @@ static int diff_delta__from_two( delta->old_file.size = old_entry->file_size; delta->old_file.mode = old_mode; git_oid_cpy(&delta->old_file.id, old_id); + delta->old_file.id_abbrev = GIT_OID_HEXSZ; delta->old_file.flags |= GIT_DIFF_FLAG_VALID_ID | GIT_DIFF_FLAG_EXISTS; } if (!git_index_entry_is_conflict(new_entry)) { git_oid_cpy(&delta->new_file.id, new_id); + delta->new_file.id_abbrev = GIT_OID_HEXSZ; delta->new_file.size = new_entry->file_size; delta->new_file.mode = new_mode; delta->old_file.flags |= GIT_DIFF_FLAG_EXISTS; diff --git a/src/diff_file.c b/src/diff_file.c index ecc34cf55..8b945a5b7 100644 --- a/src/diff_file.c +++ b/src/diff_file.c @@ -149,12 +149,14 @@ int git_diff_file_content__init_from_src( if (src->blob) { fc->file->size = git_blob_rawsize(src->blob); git_oid_cpy(&fc->file->id, git_blob_id(src->blob)); + fc->file->id_abbrev = GIT_OID_HEXSZ; fc->map.len = (size_t)fc->file->size; fc->map.data = (char *)git_blob_rawcontent(src->blob); } else { fc->file->size = src->buflen; git_odb_hash(&fc->file->id, src->buf, src->buflen, GIT_OBJ_BLOB); + fc->file->id_abbrev = GIT_OID_HEXSZ; fc->map.len = src->buflen; fc->map.data = (char *)src->buf; diff --git a/src/diff_print.c b/src/diff_print.c index 09bf77aef..7c9af2449 100644 --- a/src/diff_print.c +++ b/src/diff_print.c @@ -208,6 +208,7 @@ static int diff_print_one_raw( { diff_print_info *pi = data; git_buf *out = pi->buf; + int id_abbrev; char code = git_diff_status_char(delta->status); char start_oid[GIT_OID_HEXSZ+1], end_oid[GIT_OID_HEXSZ+1]; @@ -218,6 +219,16 @@ static int diff_print_one_raw( git_buf_clear(out); + id_abbrev = delta->old_file.mode ? delta->old_file.id_abbrev : + delta->new_file.id_abbrev; + + if (pi->oid_strlen - 1 > id_abbrev) { + giterr_set(GITERR_PATCH, + "The patch input contains %d id characters (cannot print %d)", + id_abbrev, pi->oid_strlen); + return -1; + } + git_oid_tostr(start_oid, pi->oid_strlen, &delta->old_file.id); git_oid_tostr(end_oid, pi->oid_strlen, &delta->new_file.id); @@ -252,6 +263,22 @@ static int diff_print_oid_range( { char start_oid[GIT_OID_HEXSZ+1], end_oid[GIT_OID_HEXSZ+1]; + if (delta->old_file.mode && + oid_strlen - 1 > delta->old_file.id_abbrev) { + giterr_set(GITERR_PATCH, + "The patch input contains %d id characters (cannot print %d)", + delta->old_file.id_abbrev, oid_strlen); + return -1; + } + + if ((delta->new_file.mode && + oid_strlen - 1 > delta->new_file.id_abbrev)) { + giterr_set(GITERR_PATCH, + "The patch input contains %d id characters (cannot print %d)", + delta->new_file.id_abbrev, oid_strlen); + return -1; + } + git_oid_tostr(start_oid, oid_strlen, &delta->old_file.id); git_oid_tostr(end_oid, oid_strlen, &delta->new_file.id); diff --git a/src/patch_parse.c b/src/patch_parse.c index 11e26936c..323f8dc95 100644 --- a/src/patch_parse.c +++ b/src/patch_parse.c @@ -197,15 +197,11 @@ static int parse_header_oid( static int parse_header_git_index( git_patch_parsed *patch, patch_parse_ctx *ctx) { - /* - * TODO: we read the prefix provided in the diff into the delta's id - * field, but do not mark is at an abbreviated id. - */ - size_t oid_len, nid_len; - - if (parse_header_oid(&patch->base.delta->old_file.id, &oid_len, ctx) < 0 || + if (parse_header_oid(&patch->base.delta->old_file.id, + &patch->base.delta->old_file.id_abbrev, ctx) < 0 || parse_advance_expected(ctx, "..", 2) < 0 || - parse_header_oid(&patch->base.delta->new_file.id, &nid_len, ctx) < 0) + parse_header_oid(&patch->base.delta->new_file.id, + &patch->base.delta->new_file.id_abbrev, ctx) < 0) return -1; if (ctx->line_len > 0 && ctx->line[0] == ' ') {