From 43098a7f72acdde45aadbb2ed60dfa171bc03762 Mon Sep 17 00:00:00 2001 From: Runxi Yu Date: Thu, 03 Apr 2025 14:35:50 +0800 Subject: [PATCH] git2d: Use BARE to send contents too, instead of using raw write --- git2d/bare.c | 6 +++--- git2d/bare.h | 8 ++++---- git2d/main.c | 56 ++++++++++++++++++++++++++++++++++++++--------------- diff --git a/git2d/bare.c b/git2d/bare.c index 23c0352d5524c9c4d11c91dd4aa46163a143ee5e..c54ed33b462dc618338f6f58a2f04c7d98776884 100644 --- a/git2d/bare.c +++ b/git2d/bare.c @@ -318,7 +318,7 @@ return bare_get_u8(ctx, (uint8_t *)x); } bare_error -bare_put_fixed_data(struct bare_writer *ctx, uint8_t *src, uint64_t sz) +bare_put_fixed_data(struct bare_writer *ctx, const uint8_t *src, uint64_t sz) { return ctx->write(ctx->buffer, (void *)src, sz); } @@ -330,7 +330,7 @@ return ctx->read(ctx->buffer, dst, sz); } bare_error -bare_put_data(struct bare_writer *ctx, uint8_t *src, uint64_t sz) +bare_put_data(struct bare_writer *ctx, const uint8_t *src, uint64_t sz) { bare_error err = BARE_ERROR_NONE; @@ -361,7 +361,7 @@ return err; } bare_error -bare_put_str(struct bare_writer *ctx, char *src, uint64_t sz) +bare_put_str(struct bare_writer *ctx, const char *src, uint64_t sz) { if (!checkstr(src, sz)) { return BARE_ERROR_INVALID_UTF8; diff --git a/git2d/bare.h b/git2d/bare.h index 389017f0eb40053789c94e6c49b77096c41ca1f4..d494b186a04aeb130bc93c0babe79d388e5ae8ed 100644 --- a/git2d/bare.h +++ b/git2d/bare.h @@ -17,7 +17,7 @@ BARE_ERROR_BUFFER_TOO_SMALL, BARE_ERROR_INVALID_UTF8, } bare_error; -typedef bare_error (*bare_write_func)(void *buffer, void *src, uint64_t sz); +typedef bare_error (*bare_write_func)(void *buffer, const void *src, uint64_t sz); typedef bare_error (*bare_read_func)(void *buffer, void *dst, uint64_t sz); struct bare_writer { @@ -60,11 +60,11 @@ bare_error bare_put_bool(struct bare_writer *ctx, bool x); bare_error bare_get_bool(struct bare_reader *ctx, bool *x); -bare_error bare_put_fixed_data(struct bare_writer *ctx, uint8_t *src, uint64_t sz); +bare_error bare_put_fixed_data(struct bare_writer *ctx, const uint8_t *src, uint64_t sz); bare_error bare_get_fixed_data(struct bare_reader *ctx, uint8_t *dst, uint64_t sz); -bare_error bare_put_data(struct bare_writer *ctx, uint8_t *src, uint64_t sz); +bare_error bare_put_data(struct bare_writer *ctx, const uint8_t *src, uint64_t sz); bare_error bare_get_data(struct bare_reader *ctx, uint8_t *dst, uint64_t sz); -bare_error bare_put_str(struct bare_writer *ctx, char *src, uint64_t sz); +bare_error bare_put_str(struct bare_writer *ctx, const char *src, uint64_t sz); bare_error bare_get_str(struct bare_reader *ctx, char *dst, uint64_t sz); #endif /* BARE_H */ diff --git a/git2d/main.c b/git2d/main.c index 0919415f47c1fd5d9087e5343a46b46e04bcb143..91f2572e1c5e3646c96cf16ba901d36a9e554dfb 100644 --- a/git2d/main.c +++ b/git2d/main.c @@ -3,6 +3,11 @@ * SPDX-License-Identifier: AGPL-3.0-only * SPDX-FileCopyrightText: Copyright (c) 2025 Runxi Yu */ +/* + * TODO: Pool repositories (and take care of thread safety) + * libgit2 has a nice builtin per-repo cache that we could utilize this way. + */ + #include #include #include @@ -31,17 +36,34 @@ ssize_t rsz = read(io->fd, dst, sz); return (rsz == (ssize_t)sz) ? BARE_ERROR_NONE : BARE_ERROR_READ_FAILED; } +static bare_error +conn_write(void *buffer, const void *src, uint64_t sz) +{ + conn_io_t *io = buffer; + const uint8_t *data = src; + uint64_t total = 0; + + while (total < sz) { + ssize_t written = write(io->fd, data + total, sz - total); + if (written < 0) { + if (errno == EINTR) + continue; + return BARE_ERROR_WRITE_FAILED; + } + if (written == 0) + break; + total += written; + } + + return (total == sz) ? BARE_ERROR_NONE : BARE_ERROR_WRITE_FAILED; +} + void * session(void *_conn) { int conn = *(int *)_conn; free((int *)_conn); -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wunused-but-set-variable" - int ret = 0; -#pragma GCC diagnostic pop - int err; git_repository *repo = NULL; @@ -51,24 +73,27 @@ struct bare_reader reader = { .buffer = &io, .read = conn_read, }; + struct bare_writer writer = { + .buffer = &io, + .write = conn_write, + }; err = bare_get_data(&reader, (uint8_t *)path, sizeof(path) - 1); if (err != BARE_ERROR_NONE) { - ret = 10; goto close; } path[sizeof(path) - 1] = '\0'; err = git_repository_open_ext(&repo, path, GIT_REPOSITORY_OPEN_NO_SEARCH | GIT_REPOSITORY_OPEN_BARE | GIT_REPOSITORY_OPEN_NO_DOTGIT, NULL); if (err != 0) { - ret = 1; + bare_put_uint(&writer, 1); goto close; } git_object *obj = NULL; err = git_revparse_single(&obj, repo, "HEAD^{tree}"); if (err != 0) { - ret = 2; + bare_put_uint(&writer, 2); goto free_repo; } git_tree *tree = (git_tree *) obj; @@ -76,30 +101,32 @@ git_tree_entry *entry = NULL; err = git_tree_entry_bypath(&entry, tree, "README.md"); if (err != 0) { - ret = 3; + bare_put_uint(&writer, 3); goto free_tree; } git_otype objtype = git_tree_entry_type(entry); if (objtype != GIT_OBJECT_BLOB) { - ret = 4; + bare_put_uint(&writer, 4); goto free_tree_entry; } git_object *obj2 = NULL; err = git_tree_entry_to_object(&obj2, repo, entry); if (err != 0) { - ret = 5; + bare_put_uint(&writer, 5); goto free_tree_entry; } git_blob *blob = (git_blob *) obj2; const void *content = git_blob_rawcontent(blob); if (content == NULL) { - ret = 6; + bare_put_uint(&writer, 6); goto free_blob; } - write(conn, content, git_blob_rawsize(blob)); + + bare_put_uint(&writer, 0); + bare_put_data(&writer, content, git_blob_rawsize(blob)); free_blob: git_blob_free(blob); @@ -111,9 +138,6 @@ free_repo: git_repository_free(repo); close: - // TODO: Implement proper error handling - dprintf(conn, "%d\n", ret); - close(conn); return NULL; -- 2.48.1