Lindenii Project Forge
Login

server

Lindenii Forge’s main backend daemon

Warning: Due to various recent migrations, viewing non-HEAD refs may be broken.

/git2d/cmd_commit.c (raw)

/*-
 * SPDX-License-Identifier: AGPL-3.0-only
 * SPDX-FileCopyrightText: Copyright (c) 2025 Runxi Yu <https://runxiyu.org>
 */

#include "x.h"

int cmd_commit_tree_oid(git_repository *repo, struct bare_reader *reader, struct bare_writer *writer)
{
	char hex[64] = { 0 };
	if (bare_get_data(reader, (uint8_t *) hex, sizeof(hex) - 1) != BARE_ERROR_NONE) {
		bare_put_uint(writer, 11);
		return -1;
	}
	git_oid oid;
	if (git_oid_fromstr(&oid, hex) != 0) {
		bare_put_uint(writer, 14);
		return -1;
	}
	git_commit *commit = NULL;
	if (git_commit_lookup(&commit, repo, &oid) != 0) {
		bare_put_uint(writer, 14);
		return -1;
	}
	git_tree *tree = NULL;
	if (git_commit_tree(&tree, commit) != 0) {
		git_commit_free(commit);
		bare_put_uint(writer, 14);
		return -1;
	}
	const git_oid *toid = git_tree_id(tree);
	bare_put_uint(writer, 0);
	bare_put_data(writer, toid->id, GIT_OID_RAWSZ);
	git_tree_free(tree);
	git_commit_free(commit);
	return 0;
}

int cmd_commit_create(git_repository *repo, struct bare_reader *reader, struct bare_writer *writer)
{
	char treehex[64] = { 0 };
	if (bare_get_data(reader, (uint8_t *) treehex, sizeof(treehex) - 1) != BARE_ERROR_NONE) {
		bare_put_uint(writer, 11);
		return -1;
	}
	git_oid tree_oid;
	if (git_oid_fromstr(&tree_oid, treehex) != 0) {
		bare_put_uint(writer, 15);
		return -1;
	}
	uint64_t pcnt = 0;
	if (bare_get_uint(reader, &pcnt) != BARE_ERROR_NONE) {
		bare_put_uint(writer, 11);
		return -1;
	}
	git_commit **parents = NULL;
	if (pcnt > 0) {
		parents = (git_commit **) calloc(pcnt, sizeof(git_commit *));
		if (!parents) {
			bare_put_uint(writer, 15);
			return -1;
		}
		for (uint64_t i = 0; i < pcnt; i++) {
			char phex[64] = { 0 };
			if (bare_get_data(reader, (uint8_t *) phex, sizeof(phex) - 1) != BARE_ERROR_NONE) {
				bare_put_uint(writer, 11);
				goto fail;
			}
			git_oid poid;
			if (git_oid_fromstr(&poid, phex) != 0) {
				bare_put_uint(writer, 15);
				goto fail;
			}
			if (git_commit_lookup(&parents[i], repo, &poid) != 0) {
				bare_put_uint(writer, 15);
				goto fail;
			}
		}
	}
	char aname[512] = { 0 };
	char aemail[512] = { 0 };
	if (bare_get_data(reader, (uint8_t *) aname, sizeof(aname) - 1) != BARE_ERROR_NONE) {
		bare_put_uint(writer, 11);
		goto fail;
	}
	if (bare_get_data(reader, (uint8_t *) aemail, sizeof(aemail) - 1) != BARE_ERROR_NONE) {
		bare_put_uint(writer, 11);
		goto fail;
	}
	int64_t when = 0;
	int64_t tzoff = 0;
	if (bare_get_i64(reader, &when) != BARE_ERROR_NONE) {
		bare_put_uint(writer, 11);
		goto fail;
	}
	if (bare_get_i64(reader, &tzoff) != BARE_ERROR_NONE) {
		bare_put_uint(writer, 11);
		goto fail;
	}
	char *message = NULL;
	{
		uint64_t msz = 0;
		if (bare_get_uint(reader, &msz) != BARE_ERROR_NONE) {
			bare_put_uint(writer, 11);
			goto fail;
		}
		message = (char *)malloc(msz + 1);
		if (!message) {
			bare_put_uint(writer, 15);
			goto fail;
		}
		if (bare_get_fixed_data(reader, (uint8_t *) message, msz) != BARE_ERROR_NONE) {
			free(message);
			bare_put_uint(writer, 11);
			goto fail;
		}
		message[msz] = '\0';
	}
	git_signature *sig = NULL;
	if (git_signature_new(&sig, aname, aemail, (git_time_t) when, (int)tzoff) != 0) {
		free(message);
		bare_put_uint(writer, 19);
		goto fail;
	}
	git_tree *tree = NULL;
	if (git_tree_lookup(&tree, repo, &tree_oid) != 0) {
		git_signature_free(sig);
		free(message);
		bare_put_uint(writer, 19);
		goto fail;
	}
	git_oid out;
	int rc = git_commit_create(&out, repo, NULL, sig, sig, NULL, message, tree,
				   (int)pcnt, (const git_commit **)parents);
	git_tree_free(tree);
	git_signature_free(sig);
	free(message);
	if (rc != 0) {
		bare_put_uint(writer, 19);
		goto fail;
	}
	bare_put_uint(writer, 0);
	bare_put_data(writer, out.id, GIT_OID_RAWSZ);
	if (parents) {
		for (uint64_t i = 0; i < pcnt; i++)
			if (parents[i])
				git_commit_free(parents[i]);
		free(parents);
	}
	return 0;
 fail:
	if (parents) {
		for (uint64_t i = 0; i < pcnt; i++)
			if (parents[i])
				git_commit_free(parents[i]);
		free(parents);
	}
	return -1;
}

int cmd_update_ref(git_repository *repo, struct bare_reader *reader, struct bare_writer *writer)
{
	char refname[4096] = { 0 };
	char commithex[64] = { 0 };
	if (bare_get_data(reader, (uint8_t *) refname, sizeof(refname) - 1) != BARE_ERROR_NONE) {
		bare_put_uint(writer, 11);
		return -1;
	}
	if (bare_get_data(reader, (uint8_t *) commithex, sizeof(commithex) - 1)
	    != BARE_ERROR_NONE) {
		bare_put_uint(writer, 11);
		return -1;
	}
	git_oid oid;
	if (git_oid_fromstr(&oid, commithex) != 0) {
		bare_put_uint(writer, 18);
		return -1;
	}
	git_reference *out = NULL;
	int rc = git_reference_create(&out, repo, refname, &oid, 1, NULL);
	if (rc != 0) {
		bare_put_uint(writer, 18);
		return -1;
	}
	git_reference_free(out);
	bare_put_uint(writer, 0);
	return 0;
}