コード例 #1
0
ファイル: fetch.c プロジェクト: 0CV0/libgit2
static int filter_wants(git_remote *remote)
{
	struct filter_payload p;
	git_refspec tagspec;
	int error = -1;

	git_vector_clear(&remote->refs);
	if (git_refspec__parse(&tagspec, GIT_REFSPEC_TAGS, true) < 0)
		return error;

	/*
	 * The fetch refspec can be NULL, and what this means is that the
	 * user didn't specify one. This is fine, as it means that we're
	 * not interested in any particular branch but just the remote's
	 * HEAD, which will be stored in FETCH_HEAD after the fetch.
	 */
	p.tagspec = &tagspec;
	p.found_head = 0;
	p.remote = remote;

	if (git_repository_odb__weakptr(&p.odb, remote->repo) < 0)
		goto cleanup;

	error = git_remote_ls(remote, filter_ref__cb, &p);

cleanup:
	git_refspec__free(&tagspec);

	return error;
}
コード例 #2
0
ファイル: tag.c プロジェクト: yuanms2/libgit2
static int write_tag_annotation(
    git_oid *oid,
    git_repository *repo,
    const char *tag_name,
    const git_object *target,
    const git_signature *tagger,
    const char *message)
{
    git_buf tag = GIT_BUF_INIT;
    git_odb *odb;

    git_oid__writebuf(&tag, "object ", git_object_id(target));
    git_buf_printf(&tag, "type %s\n", git_object_type2string(git_object_type(target)));
    git_buf_printf(&tag, "tag %s\n", tag_name);
    git_signature__writebuf(&tag, "tagger ", tagger);
    git_buf_putc(&tag, '\n');

    if (git_buf_puts(&tag, message) < 0)
        goto on_error;

    if (git_repository_odb__weakptr(&odb, repo) < 0)
        goto on_error;

    if (git_odb_write(oid, odb, tag.ptr, tag.size, GIT_OBJ_TAG) < 0)
        goto on_error;

    git_buf_free(&tag);
    return 0;

on_error:
    git_buf_free(&tag);
    giterr_set(GITERR_OBJECT, "Failed to create tag annotation.");
    return -1;
}
コード例 #3
0
ファイル: commit.c プロジェクト: ChloeKo/libgit2
static int git_commit__create_internal(
	git_oid *id,
	git_repository *repo,
	const char *update_ref,
	const git_signature *author,
	const git_signature *committer,
	const char *message_encoding,
	const char *message,
	const git_oid *tree,
	git_commit_parent_callback parent_cb,
	void *parent_payload,
	bool validate)
{
	int error;
	git_odb *odb;
	git_reference *ref = NULL;
	git_buf buf = GIT_BUF_INIT;
	const git_oid *current_id = NULL;
	git_array_oid_t parents = GIT_ARRAY_INIT;

	if (update_ref) {
		error = git_reference_lookup_resolved(&ref, repo, update_ref, 10);
		if (error < 0 && error != GIT_ENOTFOUND)
			return error;
	}
	giterr_clear();

	if (ref)
		current_id = git_reference_target(ref);

	if ((error = validate_tree_and_parents(&parents, repo, tree, parent_cb, parent_payload, current_id, validate)) < 0)
		goto cleanup;

	error = git_commit__create_buffer_internal(&buf, author, committer,
						   message_encoding, message, tree,
						   &parents);

	if (error < 0)
		goto cleanup;

	if (git_repository_odb__weakptr(&odb, repo) < 0)
		goto cleanup;

	if (git_odb_write(id, odb, buf.ptr, buf.size, GIT_OBJ_COMMIT) < 0)
		goto cleanup;


	if (update_ref != NULL) {
		error = git_reference__update_for_commit(
			repo, ref, update_ref, id, "commit");
		goto cleanup;
	}

cleanup:
	git_array_clear(parents);
	git_reference_free(ref);
	git_buf_free(&buf);
	return error;
}
コード例 #4
0
int git_repository_odb(git_odb **out, git_repository *repo)
{
	if (git_repository_odb__weakptr(out, repo) < 0)
		return -1;

	GIT_REFCOUNT_INC(*out);
	return 0;
}
コード例 #5
0
ファイル: blob.c プロジェクト: 0CV0/libgit2
static int blob_create_internal(git_oid *oid, git_repository *repo, const char *content_path, const char *hint_path, bool try_load_filters)
{
	int error;
	struct stat st;
	git_odb *odb = NULL;
	git_off_t size;

	assert(hint_path || !try_load_filters);

	if ((error = git_path_lstat(content_path, &st)) < 0 || (error = git_repository_odb__weakptr(&odb, repo)) < 0)
		return error;

	size = st.st_size;

	if (S_ISLNK(st.st_mode)) {
		error = write_symlink(oid, odb, content_path, (size_t)size);
	} else {
		git_vector write_filters = GIT_VECTOR_INIT;
		int filter_count = 0;

		if (try_load_filters) {
			/* Load the filters for writing this file to the ODB */
			filter_count = git_filters_load(
				&write_filters, repo, hint_path, GIT_FILTER_TO_ODB);
		}

		if (filter_count < 0) {
			/* Negative value means there was a critical error */
			error = filter_count;
		} else if (filter_count == 0) {
			/* No filters need to be applied to the document: we can stream
			 * directly from disk */
			error = write_file_stream(oid, odb, content_path, size);
		} else {
			/* We need to apply one or more filters */
			error = write_file_filtered(oid, odb, content_path, &write_filters);
		}

		git_filters_free(&write_filters);

		/*
		 * TODO: eventually support streaming filtered files, for files
		 * which are bigger than a given threshold. This is not a priority
		 * because applying a filter in streaming mode changes the final
		 * size of the blob, and without knowing its final size, the blob
		 * cannot be written in stream mode to the ODB.
		 *
		 * The plan is to do streaming writes to a tempfile on disk and then
		 * opening streaming that file to the ODB, using
		 * `write_file_stream`.
		 *
		 * CAREFULLY DESIGNED APIS YO
		 */
	}

	return error;
}
コード例 #6
0
ファイル: simple.c プロジェクト: CodeSmithyIDE/libgit2
static void setup_backend(const fake_object *objs)
{
	git_odb_backend *backend;

	cl_git_pass(build_fake_backend(&backend, objs));

	cl_git_pass(git_repository_odb__weakptr(&_odb, _repo));
	cl_git_pass(git_odb_add_backend(_odb, backend, 10));
}
コード例 #7
0
ファイル: loose.c プロジェクト: CodeSmithyIDE/libgit2
void test_odb_loose__fsync_obeys_repo_setting(void)
{
	git_repository *repo;
	git_odb *odb;
	git_oid oid;

	cl_git_pass(git_repository_init(&repo, "test-objects", 1));
	cl_git_pass(git_repository_odb__weakptr(&odb, repo));
	cl_git_pass(git_odb_write(&oid, odb, "No fsync here\n", 14, GIT_OBJECT_BLOB));
	cl_assert(p_fsync__cnt == 0);
	git_repository_free(repo);

	cl_git_pass(git_repository_open(&repo, "test-objects"));
	cl_repo_set_bool(repo, "core.fsyncObjectFiles", true);
	cl_git_pass(git_repository_odb__weakptr(&odb, repo));
	cl_git_pass(git_odb_write(&oid, odb, "Now fsync\n", 10, GIT_OBJECT_BLOB));
	cl_assert(p_fsync__cnt > 0);
	git_repository_free(repo);
}
コード例 #8
0
ファイル: commit.c プロジェクト: duralog/node-sencillo
int git_commit_create(
		git_oid *oid,
		git_repository *repo,
		const char *update_ref,
		const git_signature *author,
		const git_signature *committer,
		const char *message_encoding,
		const char *message,
		const git_tree *tree,
		int parent_count,
		const git_commit *parents[])
{
	git_buf commit = GIT_BUF_INIT;
	int i;
	git_odb *odb;

	assert(git_object_owner((const git_object *)tree) == repo);

	git_oid__writebuf(&commit, "tree ", git_object_id((const git_object *)tree));

	for (i = 0; i < parent_count; ++i) {
		assert(git_object_owner((const git_object *)parents[i]) == repo);
		git_oid__writebuf(&commit, "parent ", git_object_id((const git_object *)parents[i]));
	}

	git_signature__writebuf(&commit, "author ", author);
	git_signature__writebuf(&commit, "committer ", committer);

	if (message_encoding != NULL)
		git_buf_printf(&commit, "encoding %s\n", message_encoding);

	git_buf_putc(&commit, '\n');

	if (git_buf_puts(&commit, message) < 0)
		goto on_error;

	if (git_repository_odb__weakptr(&odb, repo) < 0)
		goto on_error;

	if (git_odb_write(oid, odb, commit.ptr, commit.size, GIT_OBJ_COMMIT) < 0)
		goto on_error;

	git_buf_free(&commit);

	if (update_ref != NULL)
		return git_reference__update(repo, oid, update_ref);

	return 0;

on_error:
	git_buf_free(&commit);
	giterr_set(GITERR_OBJECT, "Failed to create commit.");
	return -1;
}
コード例 #9
0
ファイル: diff_file.c プロジェクト: 0CV0/libgit2
static int diff_file_content_load_blob(git_diff_file_content *fc)
{
	int error = 0;
	git_odb_object *odb_obj = NULL;

	if (git_oid_iszero(&fc->file->oid))
		return 0;

	if (fc->file->mode == GIT_FILEMODE_COMMIT)
		return diff_file_content_commit_to_str(fc, false);

	/* if we don't know size, try to peek at object header first */
	if (!fc->file->size) {
		git_odb *odb;
		size_t len;
		git_otype type;

		if (!(error = git_repository_odb__weakptr(&odb, fc->repo))) {
			error = git_odb__read_header_or_object(
				&odb_obj, &len, &type, odb, &fc->file->oid);
			git_odb_free(odb);
		}
		if (error)
			return error;

		fc->file->size = len;
	}

	if (diff_file_content_binary_by_size(fc))
		return 0;

	if (odb_obj != NULL) {
		error = git_object__from_odb_object(
			(git_object **)&fc->blob, fc->repo, odb_obj, GIT_OBJ_BLOB);
		git_odb_object_free(odb_obj);
	} else {
		error = git_blob_lookup(
			(git_blob **)&fc->blob, fc->repo, &fc->file->oid);
	}

	if (!error) {
		fc->flags |= GIT_DIFF_FLAG__FREE_BLOB;
		fc->map.data = (void *)git_blob_rawcontent(fc->blob);
		fc->map.len  = (size_t)git_blob_rawsize(fc->blob);
	}

	return error;
}
コード例 #10
0
ファイル: blob.c プロジェクト: brodie/libgit2
int git_blob_create_frombuffer(git_oid *oid, git_repository *repo, const void *buffer, size_t len)
{
	int error;
	git_odb *odb;
	git_odb_stream *stream;

	if ((error = git_repository_odb__weakptr(&odb, repo)) < 0 ||
		(error = git_odb_open_wstream(&stream, odb, len, GIT_OBJ_BLOB)) < 0)
		return error;

	if ((error = git_odb_stream_write(stream, buffer, len)) == 0)
		error = git_odb_stream_finalize_write(oid, stream);

	git_odb_stream_free(stream);
	return error;
}
コード例 #11
0
ファイル: fetch.c プロジェクト: AlexShiLucky/luapower-all
static int filter_wants(git_remote *remote)
{
	git_remote_head **heads;
	git_refspec tagspec, head;
	int error = 0;
	git_odb *odb;
	size_t i, heads_len;

	git_vector_clear(&remote->refs);
	if ((error = git_refspec__parse(&tagspec, GIT_REFSPEC_TAGS, true)) < 0)
		return error;

	/*
	 * The fetch refspec can be NULL, and what this means is that the
	 * user didn't specify one. This is fine, as it means that we're
	 * not interested in any particular branch but just the remote's
	 * HEAD, which will be stored in FETCH_HEAD after the fetch.
	 */
	if (remote->active_refspecs.length == 0) {
		if ((error = git_refspec__parse(&head, "HEAD", true)) < 0)
			goto cleanup;

		error = git_refspec__dwim_one(&remote->active_refspecs, &head, &remote->refs);
		git_refspec__free(&head);

		if (error < 0)
			goto cleanup;
	}

	if (git_repository_odb__weakptr(&odb, remote->repo) < 0)
		goto cleanup;

	if (git_remote_ls((const git_remote_head ***)&heads, &heads_len, remote) < 0)
		goto cleanup;

	for (i = 0; i < heads_len; i++) {
		if ((error = maybe_want(remote, heads[i], odb, &tagspec)) < 0)
			break;
	}

cleanup:
	git_refspec__free(&tagspec);

	return error;
}
コード例 #12
0
ファイル: commit.c プロジェクト: CodeSmithyIDE/libgit2
int git_commit_create_with_signature(
	git_oid *out,
	git_repository *repo,
	const char *commit_content,
	const char *signature,
	const char *signature_field)
{
	git_odb *odb;
	int error = 0;
	const char *field;
	const char *header_end;
	git_buf commit = GIT_BUF_INIT;

	/* We start by identifying the end of the commit header */
	header_end = strstr(commit_content, "\n\n");
	if (!header_end) {
		giterr_set(GITERR_INVALID, "malformed commit contents");
		return -1;
	}

	field = signature_field ? signature_field : "gpgsig";

	/* The header ends after the first LF */
	header_end++;
	git_buf_put(&commit, commit_content, header_end - commit_content);
	format_header_field(&commit, field, signature);
	git_buf_puts(&commit, header_end);

	if (git_buf_oom(&commit))
		return -1;

	if ((error = git_repository_odb__weakptr(&odb, repo)) < 0)
		goto cleanup;

	if ((error = git_odb_write(out, odb, commit.ptr, commit.size, GIT_OBJECT_COMMIT)) < 0)
		goto cleanup;

cleanup:
	git_buf_dispose(&commit);
	return error;
}
コード例 #13
0
ファイル: repository.c プロジェクト: Asquera/libgit2
int git_repository_head_detached(git_repository *repo)
{
	git_reference *ref;
	git_odb *odb = NULL;
	int exists;

	if (git_repository_odb__weakptr(&odb, repo) < 0)
		return -1;

	if (git_reference_lookup(&ref, repo, GIT_HEAD_FILE) < 0)
		return -1;

	if (git_reference_type(ref) == GIT_REF_SYMBOLIC) {
		git_reference_free(ref);
		return 0;
	}

	exists = git_odb_exists(odb, git_reference_oid(ref));

	git_reference_free(ref);
	return exists;
}
コード例 #14
0
ファイル: fetch.c プロジェクト: DJHartley/libgit2
static int filter_wants(git_remote *remote)
{
	int error;
	struct filter_payload p;

	git_vector_clear(&remote->refs);

	/*
	 * The fetch refspec can be NULL, and what this means is that the
	 * user didn't specify one. This is fine, as it means that we're
	 * not interested in any particular branch but just the remote's
	 * HEAD, which will be stored in FETCH_HEAD after the fetch.
	 */
	p.spec = git_remote_fetchspec(remote);
	p.found_head = 0;
	p.remote = remote;

	error = git_repository_odb__weakptr(&p.odb, remote->repo);
	if (error < GIT_SUCCESS)
		return error;

	return remote->transport->ls(remote->transport, &filter_ref__cb, &p);
}
コード例 #15
0
ファイル: object.c プロジェクト: Arhzi/libgit2
bool git_object__is_valid(
	git_repository *repo, const git_oid *id, git_otype expected_type)
{
	git_odb *odb;
	git_otype actual_type;
	size_t len;
	int error;

	if (!git_object__strict_input_validation)
		return true;

	if ((error = git_repository_odb__weakptr(&odb, repo)) < 0 ||
		(error = git_odb_read_header(&len, &actual_type, odb, id)) < 0)
		return false;

	if (expected_type != GIT_OBJ_ANY && expected_type != actual_type) {
		giterr_set(GITERR_INVALID,
			"the requested type does not match the type in the ODB");
		return false;
	}

	return true;
}
コード例 #16
0
ファイル: refs.c プロジェクト: ANNAVARAMVENKATESH/libgit2
int git_reference_create(
	git_reference **ref_out,
	git_repository *repo,
	const char *name,
	const git_oid *oid,
	int force)
{
	git_odb *odb;
	int error = 0;

	assert(repo && name && oid);

	/* Sanity check the reference being created - target must exist. */
	if ((error = git_repository_odb__weakptr(&odb, repo)) < 0)
		return error;

	if (!git_odb_exists(odb, oid)) {
		giterr_set(GITERR_REFERENCE,
			"Target OID for the reference doesn't exist on the repository");
		return -1;
	}

	return reference__create(ref_out, repo, name, oid, NULL, force);
}
コード例 #17
0
ファイル: commit.c プロジェクト: CodeSmithyIDE/libgit2
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_clear(signature);
	git_buf_clear(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_OBJECT_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++;
		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;

		error = git_buf_puts(signed_data, eol+1);
		git_odb_object_free(obj);
		return error;
	}

	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;
}
コード例 #18
0
ファイル: commit.c プロジェクト: Factoid/sonic-pi
static int git_commit__create_internal(
    git_oid *id,
    git_repository *repo,
    const char *update_ref,
    const git_signature *author,
    const git_signature *committer,
    const char *message_encoding,
    const char *message,
    const git_oid *tree,
    git_commit_parent_callback parent_cb,
    void *parent_payload,
    bool validate)
{
    git_reference *ref = NULL;
    int error = 0, matched_parent = 0;
    const git_oid *current_id = NULL;
    git_buf commit = GIT_BUF_INIT;
    size_t i = 0;
    git_odb *odb;
    const git_oid *parent;

    assert(id && repo && tree && parent_cb);

    if (validate && !git_object__is_valid(repo, tree, GIT_OBJ_TREE))
        return -1;

    if (update_ref) {
        error = git_reference_lookup_resolved(&ref, repo, update_ref, 10);
        if (error < 0 && error != GIT_ENOTFOUND)
            return error;
    }
    giterr_clear();

    if (ref)
        current_id = git_reference_target(ref);

    git_oid__writebuf(&commit, "tree ", tree);

    while ((parent = parent_cb(i, parent_payload)) != NULL) {
        if (validate && !git_object__is_valid(repo, parent, GIT_OBJ_COMMIT)) {
            error = -1;
            goto on_error;
        }

        git_oid__writebuf(&commit, "parent ", parent);
        if (i == 0 && current_id && git_oid_equal(current_id, parent))
            matched_parent = 1;
        i++;
    }

    if (ref && !matched_parent) {
        git_reference_free(ref);
        git_buf_free(&commit);
        giterr_set(GITERR_OBJECT, "failed to create commit: current tip is not the first parent");
        return GIT_EMODIFIED;
    }

    git_signature__writebuf(&commit, "author ", author);
    git_signature__writebuf(&commit, "committer ", committer);

    if (message_encoding != NULL)
        git_buf_printf(&commit, "encoding %s\n", message_encoding);

    git_buf_putc(&commit, '\n');

    if (git_buf_puts(&commit, message) < 0)
        goto on_error;

    if (git_repository_odb__weakptr(&odb, repo) < 0)
        goto on_error;

    if (git_odb_write(id, odb, commit.ptr, commit.size, GIT_OBJ_COMMIT) < 0)
        goto on_error;

    git_buf_free(&commit);

    if (update_ref != NULL) {
        error = git_reference__update_for_commit(
                    repo, ref, update_ref, id, "commit");
        git_reference_free(ref);
        return error;
    }

    return 0;

on_error:
    git_buf_free(&commit);
    return -1;
}
コード例 #19
0
ファイル: refs.c プロジェクト: DavidMolinari/sonic-pi
static int reference__create(
	git_reference **ref_out,
	git_repository *repo,
	const char *name,
	const git_oid *oid,
	const char *symbolic,
	int force,
	const git_signature *signature,
	const char *log_message,
	const git_oid *old_id,
	const char *old_target)
{
	git_refname_t normalized;
	git_refdb *refdb;
	git_reference *ref = NULL;
	int error = 0;

	assert(repo && name);
	assert(symbolic || signature);

	if (ref_out)
		*ref_out = NULL;

	error = reference_normalize_for_repo(normalized, repo, name);
	if (error < 0)
		return error;

	error = git_repository_refdb__weakptr(&refdb, repo);
	if (error < 0)
		return error;

	if (oid != NULL) {
		git_odb *odb;

		assert(symbolic == NULL);

		/* Sanity check the reference being created - target must exist. */
		if ((error = git_repository_odb__weakptr(&odb, repo)) < 0)
			return error;

		if (!git_odb_exists(odb, oid)) {
			giterr_set(GITERR_REFERENCE,
				"Target OID for the reference doesn't exist on the repository");
			return -1;
		}

		ref = git_reference__alloc(normalized, oid, NULL);
	} else {
		git_refname_t normalized_target;

		if ((error = reference_normalize_for_repo(normalized_target, repo, symbolic)) < 0)
			return error;

		ref = git_reference__alloc_symbolic(normalized, normalized_target);
	}

	GITERR_CHECK_ALLOC(ref);

	if ((error = git_refdb_write(refdb, ref, force, signature, log_message, old_id, old_target)) < 0) {
		git_reference_free(ref);
		return error;
	}

	if (ref_out == NULL)
		git_reference_free(ref);
	else
		*ref_out = ref;

	return 0;
}
コード例 #20
0
ファイル: object.c プロジェクト: DaneTheory/libgit2
int git_object_lookup_prefix(
	git_object **object_out,
	git_repository *repo,
	const git_oid *id,
	size_t len,
	git_otype type)
{
	git_object *object = NULL;
	git_odb *odb = NULL;
	git_odb_object *odb_obj = NULL;
	int error = 0;

	assert(repo && object_out && id);

	if (len < GIT_OID_MINPREFIXLEN) {
		giterr_set(GITERR_OBJECT, "Ambiguous lookup - OID prefix is too short");
		return GIT_EAMBIGUOUS;
	}

	error = git_repository_odb__weakptr(&odb, repo);
	if (error < 0)
		return error;

	if (len > GIT_OID_HEXSZ)
		len = GIT_OID_HEXSZ;

	if (len == GIT_OID_HEXSZ) {
		git_cached_obj *cached = NULL;

		/* We want to match the full id : we can first look up in the cache,
		 * since there is no need to check for non ambiguousity
		 */
		cached = git_cache_get_any(&repo->objects, id);
		if (cached != NULL) {
			if (cached->flags == GIT_CACHE_STORE_PARSED) {
				object = (git_object *)cached;

				if (type != GIT_OBJ_ANY && type != object->cached.type) {
					git_object_free(object);
					giterr_set(GITERR_INVALID,
						"The requested type does not match the type in ODB");
					return GIT_ENOTFOUND;
				}

				*object_out = object;
				return 0;
			} else if (cached->flags == GIT_CACHE_STORE_RAW) {
				odb_obj = (git_odb_object *)cached;
			} else {
				assert(!"Wrong caching type in the global object cache");
			}
		} else {
			/* Object was not found in the cache, let's explore the backends.
			 * We could just use git_odb_read_unique_short_oid,
			 * it is the same cost for packed and loose object backends,
			 * but it may be much more costly for sqlite and hiredis.
			 */
			error = git_odb_read(&odb_obj, odb, id);
		}
	} else {
		git_oid short_oid;

		/* We copy the first len*4 bits from id and fill the remaining with 0s */
		memcpy(short_oid.id, id->id, (len + 1) / 2);
		if (len % 2)
			short_oid.id[len / 2] &= 0xF0;
		memset(short_oid.id + (len + 1) / 2, 0, (GIT_OID_HEXSZ - len) / 2);

		/* If len < GIT_OID_HEXSZ (a strict short oid was given), we have
		 * 2 options :
		 * - We always search in the cache first. If we find that short oid is
		 *	ambiguous, we can stop. But in all the other cases, we must then
		 *	explore all the backends (to find an object if there was match,
		 *	or to check that oid is not ambiguous if we have found 1 match in
		 *	the cache)
		 * - We never explore the cache, go right to exploring the backends
		 * We chose the latter : we explore directly the backends.
		 */
		error = git_odb_read_prefix(&odb_obj, odb, &short_oid, len);
	}

	if (error < 0)
		return error;

	error = git_object__from_odb_object(object_out, repo, odb_obj, type);

	git_odb_object_free(odb_obj);

	return error;
}
コード例 #21
0
ファイル: tag.c プロジェクト: yuanms2/libgit2
int git_tag_create_frombuffer(git_oid *oid, git_repository *repo, const char *buffer, int allow_ref_overwrite)
{
    git_tag tag;
    int error;
    git_odb *odb;
    git_odb_stream *stream;
    git_odb_object *target_obj;

    git_reference *new_ref = NULL;
    git_buf ref_name = GIT_BUF_INIT;

    assert(oid && buffer);

    memset(&tag, 0, sizeof(tag));

    if (git_repository_odb__weakptr(&odb, repo) < 0)
        return -1;

    /* validate the buffer */
    if (tag_parse(&tag, buffer, buffer + strlen(buffer)) < 0)
        return -1;

    /* validate the target */
    if (git_odb_read(&target_obj, odb, &tag.target) < 0)
        goto on_error;

    if (tag.type != target_obj->cached.type) {
        giterr_set(GITERR_TAG, "The type for the given target is invalid");
        goto on_error;
    }

    error = retrieve_tag_reference_oid(oid, &ref_name, repo, tag.tag_name);
    if (error < 0 && error != GIT_ENOTFOUND)
        goto on_error;

    /* We don't need these objects after this */
    git_signature_free(tag.tagger);
    git__free(tag.tag_name);
    git__free(tag.message);
    git_odb_object_free(target_obj);

    /** Ensure the tag name doesn't conflict with an already existing
     *	reference unless overwriting has explicitly been requested **/
    if (error == 0 && !allow_ref_overwrite) {
        giterr_set(GITERR_TAG, "Tag already exists");
        return GIT_EEXISTS;
    }

    /* write the buffer */
    if ((error = git_odb_open_wstream(
                     &stream, odb, strlen(buffer), GIT_OBJ_TAG)) < 0)
        return error;

    if (!(error = git_odb_stream_write(stream, buffer, strlen(buffer))))
        error = git_odb_stream_finalize_write(oid, stream);

    git_odb_stream_free(stream);

    if (error < 0) {
        git_buf_free(&ref_name);
        return error;
    }

    error = git_reference_create(
                &new_ref, repo, ref_name.ptr, oid, allow_ref_overwrite, NULL);

    git_reference_free(new_ref);
    git_buf_free(&ref_name);

    return error;

on_error:
    git_signature_free(tag.tagger);
    git__free(tag.tag_name);
    git__free(tag.message);
    git_odb_object_free(target_obj);
    return -1;
}