int git_blob_filtered_content( git_buf *out, git_blob *blob, const char *path, int check_for_binary_data) { int error = 0; git_filter_list *fl = NULL; assert(blob && path && out); git_buf_sanitize(out); if (check_for_binary_data && git_blob_is_binary(blob)) return 0; if (!(error = git_filter_list_load( &fl, git_blob_owner(blob), blob, path, GIT_FILTER_TO_WORKTREE, GIT_FILTER_DEFAULT))) { error = git_filter_list_apply_to_blob(out, fl, blob); git_filter_list_free(fl); } return error; }
static int refspec_transform( git_buf *out, const char *from, const char *to, const char *name) { const char *from_star, *to_star; size_t replacement_len, star_offset; git_buf_sanitize(out); git_buf_clear(out); /* * There are two parts to each side of a refspec, the bit * before the star and the bit after it. The star can be in * the middle of the pattern, so we need to look at each bit * individually. */ from_star = strchr(from, '*'); to_star = strchr(to, '*'); assert(from_star && to_star); /* star offset, both in 'from' and in 'name' */ star_offset = from_star - from; /* the first half is copied over */ git_buf_put(out, to, to_star - to); /* * Copy over the name, but exclude the trailing part in "from" starting * after the glob */ replacement_len = strlen(name + star_offset) - strlen(from_star + 1); git_buf_put(out, name + star_offset, replacement_len); return git_buf_puts(out, to_star + 1); }
static int refspec_transform( git_buf *out, const char *from, const char *to, const char *name) { size_t to_len = to ? strlen(to) : 0; size_t from_len = from ? strlen(from) : 0; size_t name_len = name ? strlen(name) : 0; git_buf_sanitize(out); if (git_buf_set(out, to, to_len) < 0) return -1; if (to_len > 0) { /* No '*' at the end of 'to' means that refspec is mapped to one * specific branch, so no actual transformation is needed. */ if (out->ptr[to_len - 1] != '*') return 0; git_buf_shorten(out, 1); /* remove trailing '*' copied from 'to' */ } if (from_len > 0) /* ignore trailing '*' from 'from' */ from_len--; if (from_len > name_len) from_len = name_len; return git_buf_put(out, name + from_len, name_len - from_len); }
int git_commit_header_field(git_buf *out, const git_commit *commit, const char *field) { const char *eol, *buf = commit->raw_header; git_buf_sanitize(out); while ((eol = strchr(buf, '\n'))) { /* We can skip continuations here */ if (buf[0] == ' ') { buf = eol + 1; continue; } /* Skip until we find the field we're after */ if (git__prefixcmp(buf, field)) { buf = eol + 1; continue; } buf += strlen(field); /* Check that we're not matching a prefix but the field itself */ if (buf[0] != ' ') { buf = eol + 1; continue; } buf++; /* skip the SP */ git_buf_put(out, buf, eol - buf); if (git_buf_oom(out)) goto oom; /* If the next line starts with SP, it's multi-line, we must continue */ while (eol[1] == ' ') { git_buf_putc(out, '\n'); buf = eol + 2; eol = strchr(buf, '\n'); if (!eol) goto malformed; git_buf_put(out, buf, eol - buf); } if (git_buf_oom(out)) goto oom; return 0; } giterr_set(GITERR_OBJECT, "no such field '%s'", field); return GIT_ENOTFOUND; malformed: giterr_set(GITERR_OBJECT, "malformed header"); return -1; oom: giterr_set_oom(); return -1; }
int git_refspec_rtransform(git_buf *out, const git_refspec *spec, const char *name) { git_buf_sanitize(out); if (!spec->pattern) return git_buf_puts(out, spec->src); return refspec_transform(out, spec->dst, spec->src, name); }
int git_commit_header_field(git_buf *out, const git_commit *commit, const char *field) { const char *buf = commit->raw_header; const char *h, *eol; git_buf_sanitize(out); while ((h = strchr(buf, '\n')) && h[1] != '\0' && h[1] != '\n') { h++; if (git__prefixcmp(h, field)) { buf = h; continue; } h += strlen(field); eol = strchr(h, '\n'); if (h[0] != ' ') { buf = h; continue; } if (!eol) goto malformed; h++; /* skip the SP */ git_buf_put(out, h, eol - h); if (git_buf_oom(out)) goto oom; /* If the next line starts with SP, it's multi-line, we must continue */ while (eol[1] == ' ') { git_buf_putc(out, '\n'); h = eol + 2; eol = strchr(h, '\n'); if (!eol) goto malformed; git_buf_put(out, h, eol - h); } if (git_buf_oom(out)) goto oom; return 0; } return GIT_ENOTFOUND; malformed: giterr_set(GITERR_OBJECT, "malformed header"); return -1; oom: giterr_set_oom(); return -1; }
int git_repository_discover( git_buf *out, const char *start_path, int across_fs, const char *ceiling_dirs) { uint32_t flags = across_fs ? GIT_REPOSITORY_OPEN_CROSS_FS : 0; assert(start_path); git_buf_sanitize(out); return find_repo(out, NULL, start_path, flags, ceiling_dirs); }
int git_refspec_rtransform(git_buf *out, const git_refspec *spec, const char *name) { assert(out && spec && name); git_buf_sanitize(out); if (!git_refspec_dst_matches(spec, name)) { giterr_set(GITERR_INVALID, "ref '%s' doesn't match the destination", name); return -1; } if (!spec->pattern) return git_buf_puts(out, spec->src); return refspec_transform(out, spec->dst, spec->src, name); }
int git_refspec_transform(git_buf *out, const git_refspec *spec, const char *name) { assert(out && spec && name); git_buf_sanitize(out); if (!git_refspec_src_matches(spec, name)) { git_error_set(GIT_ERROR_INVALID, "ref '%s' doesn't match the source", name); return -1; } if (!spec->pattern) return git_buf_puts(out, spec->dst ? spec->dst : ""); return refspec_transform(out, spec->src, spec->dst, name); }
static int refspec_transform( git_buf *out, const char *from, const char *to, const char *name) { const char *from_star, *to_star; const char *name_slash, *from_slash; size_t replacement_len, star_offset; git_buf_sanitize(out); git_buf_clear(out); /* * There are two parts to each side of a refspec, the bit * before the star and the bit after it. The star can be in * the middle of the pattern, so we need to look at each bit * individually. */ from_star = strchr(from, '*'); to_star = strchr(to, '*'); assert(from_star && to_star); /* star offset, both in 'from' and in 'name' */ star_offset = from_star - from; /* the first half is copied over */ git_buf_put(out, to, to_star - to); /* then we copy over the replacement, from the star's offset to the next slash in 'name' */ name_slash = strchr(name + star_offset, '/'); if (!name_slash) name_slash = strrchr(name, '\0'); /* if there is no slash after the star in 'from', we want to copy everything over */ from_slash = strchr(from + star_offset, '/'); if (!from_slash) name_slash = strrchr(name, '\0'); replacement_len = (name_slash - name) - star_offset; git_buf_put(out, name + star_offset, replacement_len); return git_buf_puts(out, to_star + 1); }
int git_object_short_id(git_buf *out, const git_object *obj) { git_repository *repo; int len = GIT_ABBREV_DEFAULT, error; git_oid id = {{0}}; git_odb *odb; assert(out && obj); git_buf_sanitize(out); repo = git_object_owner(obj); if ((error = git_repository__cvar(&len, repo, GIT_CVAR_ABBREV)) < 0) return error; if ((error = git_repository_odb(&odb, repo)) < 0) return error; while (len < GIT_OID_HEXSZ) { /* set up short oid */ memcpy(&id.id, &obj->cached.oid.id, (len + 1) / 2); if (len & 1) id.id[len / 2] &= 0xf0; error = git_odb_exists_prefix(NULL, odb, &id, len); if (error != GIT_EAMBIGUOUS) break; giterr_clear(); len++; } if (!error && !(error = git_buf_grow(out, len + 1))) { git_oid_tostr(out->ptr, len + 1, &id); out->size = len; } git_odb_free(odb); return error; }
int git_branch_upstream_remote(git_buf *buf, git_repository *repo, const char *refname) { int error; git_config *cfg; if (!git_reference__is_branch(refname)) return not_a_local_branch(refname); if ((error = git_repository_config__weakptr(&cfg, repo)) < 0) return error; git_buf_sanitize(buf); if ((error = retrieve_upstream_configuration(buf, cfg, refname, "branch.%s.remote")) < 0) return error; if (git_buf_len(buf) == 0) { giterr_set(GITERR_REFERENCE, "branch '%s' does not have an upstream remote", refname); error = GIT_ENOTFOUND; git_buf_clear(buf); } return error; }
int git_branch_remote_name(git_buf *buf, git_repository *repo, const char *refname) { git_strarray remote_list = {0}; size_t i; git_remote *remote; const git_refspec *fetchspec; int error = 0; char *remote_name = NULL; assert(buf && repo && refname); git_buf_sanitize(buf); /* Verify that this is a remote branch */ if (!git_reference__is_remote(refname)) { giterr_set(GITERR_INVALID, "Reference '%s' is not a remote branch.", refname); error = GIT_ERROR; goto cleanup; } /* Get the remotes */ if ((error = git_remote_list(&remote_list, repo)) < 0) goto cleanup; /* Find matching remotes */ for (i = 0; i < remote_list.count; i++) { if ((error = git_remote_lookup(&remote, repo, remote_list.strings[i])) < 0) continue; fetchspec = git_remote__matching_dst_refspec(remote, refname); if (fetchspec) { /* If we have not already set out yet, then set * it to the matching remote name. Otherwise * multiple remotes match this reference, and it * is ambiguous. */ if (!remote_name) { remote_name = remote_list.strings[i]; } else { git_remote_free(remote); giterr_set(GITERR_REFERENCE, "Reference '%s' is ambiguous", refname); error = GIT_EAMBIGUOUS; goto cleanup; } } git_remote_free(remote); } if (remote_name) { git_buf_clear(buf); error = git_buf_puts(buf, remote_name); } else { giterr_set(GITERR_REFERENCE, "Could not determine remote for '%s'", refname); error = GIT_ENOTFOUND; } cleanup: if (error < 0) git_buf_free(buf); git_strarray_free(&remote_list); return error; }
int git_branch_upstream_name( git_buf *out, git_repository *repo, const char *refname) { git_buf remote_name = GIT_BUF_INIT; git_buf merge_name = GIT_BUF_INIT; git_buf buf = GIT_BUF_INIT; int error = -1; git_remote *remote = NULL; const git_refspec *refspec; git_config *config; assert(out && refname); git_buf_sanitize(out); if (!git_reference__is_branch(refname)) return not_a_local_branch(refname); if ((error = git_repository_config_snapshot(&config, repo)) < 0) return error; if ((error = retrieve_upstream_configuration( &remote_name, config, refname, "branch.%s.remote")) < 0) goto cleanup; if ((error = retrieve_upstream_configuration( &merge_name, config, refname, "branch.%s.merge")) < 0) goto cleanup; if (git_buf_len(&remote_name) == 0 || git_buf_len(&merge_name) == 0) { giterr_set(GITERR_REFERENCE, "branch '%s' does not have an upstream", refname); error = GIT_ENOTFOUND; goto cleanup; } if (strcmp(".", git_buf_cstr(&remote_name)) != 0) { if ((error = git_remote_lookup(&remote, repo, git_buf_cstr(&remote_name))) < 0) goto cleanup; refspec = git_remote__matching_refspec(remote, git_buf_cstr(&merge_name)); if (!refspec) { error = GIT_ENOTFOUND; goto cleanup; } if (git_refspec_transform(&buf, refspec, git_buf_cstr(&merge_name)) < 0) goto cleanup; } else if (git_buf_set(&buf, git_buf_cstr(&merge_name), git_buf_len(&merge_name)) < 0) goto cleanup; error = git_buf_set(out, git_buf_cstr(&buf), git_buf_len(&buf)); cleanup: git_config_free(config); git_remote_free(remote); git_buf_free(&remote_name); git_buf_free(&merge_name); git_buf_free(&buf); return error; }
int git_commit_extract_signature(git_buf *signature, git_buf *signed_data, git_repository *repo, git_oid *commit_id, const char *field) { git_odb_object *obj; git_odb *odb; const char *buf; const char *h, *eol; int error; git_buf_sanitize(signature); git_buf_sanitize(signed_data); if (!field) field = "gpgsig"; if ((error = git_repository_odb__weakptr(&odb, repo)) < 0) return error; if ((error = git_odb_read(&obj, odb, commit_id)) < 0) return error; if (obj->cached.type != GIT_OBJ_COMMIT) { giterr_set(GITERR_INVALID, "the requested type does not match the type in ODB"); error = GIT_ENOTFOUND; goto cleanup; } buf = git_odb_object_data(obj); while ((h = strchr(buf, '\n')) && h[1] != '\0' && h[1] != '\n') { h++; if (git__prefixcmp(buf, field)) { if (git_buf_put(signed_data, buf, h - buf) < 0) return -1; buf = h; continue; } h = buf; h += strlen(field); eol = strchr(h, '\n'); if (h[0] != ' ') { buf = h; continue; } if (!eol) goto malformed; h++; /* skip the SP */ git_buf_put(signature, h, eol - h); if (git_buf_oom(signature)) goto oom; /* If the next line starts with SP, it's multi-line, we must continue */ while (eol[1] == ' ') { git_buf_putc(signature, '\n'); h = eol + 2; eol = strchr(h, '\n'); if (!eol) goto malformed; git_buf_put(signature, h, eol - h); } if (git_buf_oom(signature)) goto oom; git_odb_object_free(obj); return git_buf_puts(signed_data, eol+1); } giterr_set(GITERR_OBJECT, "this commit is not signed"); error = GIT_ENOTFOUND; goto cleanup; malformed: giterr_set(GITERR_OBJECT, "malformed header"); error = -1; goto cleanup; oom: giterr_set_oom(); error = -1; goto cleanup; cleanup: git_odb_object_free(obj); git_buf_clear(signature); git_buf_clear(signed_data); return error; }