diff options
Diffstat (limited to '')
-rw-r--r-- | git2d/.gitignore | 1 | ||||
-rw-r--r-- | git2d/bare.c | 309 | ||||
-rw-r--r-- | git2d/bare.h | 72 | ||||
-rw-r--r-- | git2d/cmd1.c | 129 | ||||
-rw-r--r-- | git2d/cmd2.c | 126 | ||||
-rw-r--r-- | git2d/main.c | 82 | ||||
-rw-r--r-- | git2d/rw.c | 34 | ||||
-rw-r--r-- | git2d/session.c | 78 | ||||
-rw-r--r-- | git2d/x.h | 38 |
9 files changed, 869 insertions, 0 deletions
diff --git a/git2d/.gitignore b/git2d/.gitignore new file mode 100644 index 0000000..635d84d --- /dev/null +++ b/git2d/.gitignore @@ -0,0 +1 @@ +/git2d diff --git a/git2d/bare.c b/git2d/bare.c new file mode 100644 index 0000000..b580980 --- /dev/null +++ b/git2d/bare.c @@ -0,0 +1,309 @@ +/*- + * SPDX-License-Identifier: MIT + * SPDX-FileCopyrightText: Copyright (c) 2022 Frank Smit <https://61924.nl/> + */ + +#include <string.h> +#include <stdbool.h> + +#include "bare.h" + +#define UNUSED(x) (void)(x) + +enum { + U8SZ = 1, + U16SZ = 2, + U32SZ = 4, + U64SZ = 8, + MAXVARINTSZ = 10, +}; + +bare_error bare_put_uint(struct bare_writer *ctx, uint64_t x) +{ + uint64_t i = 0; + uint8_t b[MAXVARINTSZ]; + + while (x >= 0x80) { + b[i] = (uint8_t) x | 0x80; + x >>= 7; + i++; + } + + b[i] = (uint8_t) x; + i++; + + return ctx->write(ctx->buffer, b, i); +} + +bare_error bare_get_uint(struct bare_reader *ctx, uint64_t *x) +{ + bare_error err = BARE_ERROR_NONE; + + uint8_t shift = 0; + uint64_t result = 0; + + for (uint8_t i = 0; i < 10; i++) { + uint8_t b; + + err = ctx->read(ctx->buffer, &b, U8SZ); + if (err != BARE_ERROR_NONE) { + break; + } + + if (b < 0x80) { + result |= (uint64_t) b << shift; + break; + } else { + result |= ((uint64_t) b & 0x7f) << shift; + shift += 7; + } + } + + *x = result; + + return err; +} + +bare_error bare_put_int(struct bare_writer *ctx, int64_t x) +{ + uint64_t ux = (uint64_t) x << 1; + + if (x < 0) { + ux = ~ux; + } + + return bare_put_uint(ctx, ux); +} + +bare_error bare_get_int(struct bare_reader *ctx, int64_t *x) +{ + uint64_t ux; + + bare_error err = bare_get_uint(ctx, &ux); + + if (err == BARE_ERROR_NONE) { + *x = (int64_t) (ux >> 1); + + if ((ux & 1) != 0) { + *x = ~(*x); + } + } + + return err; +} + +bare_error bare_put_u8(struct bare_writer *ctx, uint8_t x) +{ + return ctx->write(ctx->buffer, &x, U8SZ); +} + +bare_error bare_get_u8(struct bare_reader *ctx, uint8_t *x) +{ + return ctx->read(ctx->buffer, x, U8SZ); +} + +bare_error bare_put_u16(struct bare_writer *ctx, uint16_t x) +{ + return ctx->write(ctx->buffer, (uint8_t[U16SZ]) { + x, x >> 8} + , U16SZ); +} + +bare_error bare_get_u16(struct bare_reader *ctx, uint16_t *x) +{ + bare_error err = ctx->read(ctx->buffer, x, U16SZ); + + if (err == BARE_ERROR_NONE) { + *x = (uint16_t) ((uint8_t *) x)[0] + | (uint16_t) ((uint8_t *) x)[1] << 8; + } + + return err; +} + +bare_error bare_put_u32(struct bare_writer *ctx, uint32_t x) +{ + uint8_t buf[U32SZ]; + + buf[0] = (uint8_t) (x); + buf[1] = (uint8_t) (x >> 8); + buf[2] = (uint8_t) (x >> 16); + buf[3] = (uint8_t) (x >> 24); + + return ctx->write(ctx->buffer, buf, U32SZ); +} + +bare_error bare_get_u32(struct bare_reader *ctx, uint32_t *x) +{ + bare_error err = ctx->read(ctx->buffer, x, U32SZ); + + if (err == BARE_ERROR_NONE) { + *x = (uint32_t) (((uint8_t *) x)[0]) + | (uint32_t) (((uint8_t *) x)[1] << 8) + | (uint32_t) (((uint8_t *) x)[2] << 16) + | (uint32_t) (((uint8_t *) x)[3] << 24); + } + + return err; +} + +bare_error bare_put_u64(struct bare_writer *ctx, uint64_t x) +{ + uint8_t buf[U64SZ]; + + buf[0] = x; + buf[1] = x >> 8; + buf[2] = x >> 16; + buf[3] = x >> 24; + buf[4] = x >> 32; + buf[5] = x >> 40; + buf[6] = x >> 48; + buf[7] = x >> 56; + + return ctx->write(ctx->buffer, buf, U64SZ); +} + +bare_error bare_get_u64(struct bare_reader *ctx, uint64_t *x) +{ + bare_error err = ctx->read(ctx->buffer, x, U64SZ); + + if (err == BARE_ERROR_NONE) { + *x = (uint64_t) ((uint8_t *) x)[0] + | (uint64_t) ((uint8_t *) x)[1] << 8 + | (uint64_t) ((uint8_t *) x)[2] << 16 + | (uint64_t) ((uint8_t *) x)[3] << 24 + | (uint64_t) ((uint8_t *) x)[4] << 32 + | (uint64_t) ((uint8_t *) x)[5] << 40 + | (uint64_t) ((uint8_t *) x)[6] << 48 + | (uint64_t) ((uint8_t *) x)[7] << 56; + } + + return err; +} + +bare_error bare_put_i8(struct bare_writer *ctx, int8_t x) +{ + return bare_put_u8(ctx, x); +} + +bare_error bare_get_i8(struct bare_reader *ctx, int8_t *x) +{ + return bare_get_u8(ctx, (uint8_t *) x); +} + +bare_error bare_put_i16(struct bare_writer *ctx, int16_t x) +{ + return bare_put_u16(ctx, x); +} + +bare_error bare_get_i16(struct bare_reader *ctx, int16_t *x) +{ + return bare_get_u16(ctx, (uint16_t *) x); +} + +bare_error bare_put_i32(struct bare_writer *ctx, int32_t x) +{ + return bare_put_u32(ctx, x); +} + +bare_error bare_get_i32(struct bare_reader *ctx, int32_t *x) +{ + return bare_get_u32(ctx, (uint32_t *) x); +} + +bare_error bare_put_i64(struct bare_writer *ctx, int64_t x) +{ + return bare_put_u64(ctx, x); +} + +bare_error bare_get_i64(struct bare_reader *ctx, int64_t *x) +{ + return bare_get_u64(ctx, (uint64_t *) x); +} + +bare_error bare_put_f32(struct bare_writer *ctx, float x) +{ + uint32_t b; + memcpy(&b, &x, U32SZ); + + return bare_put_u32(ctx, b); +} + +bare_error bare_get_f32(struct bare_reader *ctx, float *x) +{ + return ctx->read(ctx->buffer, x, U32SZ); +} + +bare_error bare_put_f64(struct bare_writer *ctx, double x) +{ + uint64_t b; + memcpy(&b, &x, U64SZ); + + return bare_put_u64(ctx, b); +} + +bare_error bare_get_f64(struct bare_reader *ctx, double *x) +{ + return ctx->read(ctx->buffer, x, U64SZ); +} + +bare_error bare_put_bool(struct bare_writer *ctx, bool x) +{ + return bare_put_u8(ctx, (uint8_t) x); +} + +bare_error bare_get_bool(struct bare_reader *ctx, bool *x) +{ + return bare_get_u8(ctx, (uint8_t *) x); +} + +bare_error +bare_put_fixed_data(struct bare_writer *ctx, const uint8_t *src, uint64_t sz) +{ + return ctx->write(ctx->buffer, (void *)src, sz); +} + +bare_error +bare_get_fixed_data(struct bare_reader *ctx, uint8_t *dst, uint64_t sz) +{ + return ctx->read(ctx->buffer, dst, sz); +} + +bare_error +bare_put_data(struct bare_writer *ctx, const uint8_t *src, uint64_t sz) +{ + bare_error err = BARE_ERROR_NONE; + + err = bare_put_uint(ctx, sz); + + if (err == BARE_ERROR_NONE) { + err = bare_put_fixed_data(ctx, src, sz); + } + + return err; +} + +bare_error bare_get_data(struct bare_reader *ctx, uint8_t *dst, uint64_t sz) +{ + bare_error err = BARE_ERROR_NONE; + uint64_t ssz = 0; + + err = bare_get_uint(ctx, &ssz); + + if (err == BARE_ERROR_NONE) { + err = ssz <= sz ? bare_get_fixed_data(ctx, dst, ssz) + : BARE_ERROR_BUFFER_TOO_SMALL; + } + + return err; +} + +bare_error bare_put_str(struct bare_writer *ctx, const char *src, uint64_t sz) +{ + return bare_put_data(ctx, (uint8_t *) src, sz); +} + +bare_error bare_get_str(struct bare_reader *ctx, char *dst, uint64_t sz) +{ + return bare_get_data(ctx, (uint8_t *) dst, sz); +} diff --git a/git2d/bare.h b/git2d/bare.h new file mode 100644 index 0000000..e813464 --- /dev/null +++ b/git2d/bare.h @@ -0,0 +1,72 @@ +/*- + * SPDX-License-Identifier: MIT + * SPDX-FileCopyrightText: Copyright (c) 2022 Frank Smit <https://61924.nl/> + */ + +#ifndef BARE_H +#define BARE_H + +#include <stdint.h> +#include <stdbool.h> + +typedef enum { + BARE_ERROR_NONE, + BARE_ERROR_WRITE_FAILED, + BARE_ERROR_READ_FAILED, + BARE_ERROR_BUFFER_TOO_SMALL, + BARE_ERROR_INVALID_UTF8, +} bare_error; + +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 { + void *buffer; + bare_write_func write; +}; + +struct bare_reader { + void *buffer; + bare_read_func read; +}; + +bare_error bare_put_uint(struct bare_writer *ctx, uint64_t x); /* varuint */ +bare_error bare_get_uint(struct bare_reader *ctx, uint64_t *x); /* varuint */ +bare_error bare_put_u8(struct bare_writer *ctx, uint8_t x); +bare_error bare_get_u8(struct bare_reader *ctx, uint8_t *x); +bare_error bare_put_u16(struct bare_writer *ctx, uint16_t x); +bare_error bare_get_u16(struct bare_reader *ctx, uint16_t *x); +bare_error bare_put_u32(struct bare_writer *ctx, uint32_t x); +bare_error bare_get_u32(struct bare_reader *ctx, uint32_t *x); +bare_error bare_put_u64(struct bare_writer *ctx, uint64_t x); +bare_error bare_get_u64(struct bare_reader *ctx, uint64_t *x); + +bare_error bare_put_int(struct bare_writer *ctx, int64_t x); /* varint */ +bare_error bare_get_int(struct bare_reader *ctx, int64_t *x); /* varint */ +bare_error bare_put_i8(struct bare_writer *ctx, int8_t x); +bare_error bare_get_i8(struct bare_reader *ctx, int8_t *x); +bare_error bare_put_i16(struct bare_writer *ctx, int16_t x); +bare_error bare_get_i16(struct bare_reader *ctx, int16_t *x); +bare_error bare_put_i32(struct bare_writer *ctx, int32_t x); +bare_error bare_get_i32(struct bare_reader *ctx, int32_t *x); +bare_error bare_put_i64(struct bare_writer *ctx, int64_t x); +bare_error bare_get_i64(struct bare_reader *ctx, int64_t *x); + +bare_error bare_put_f32(struct bare_writer *ctx, float x); +bare_error bare_get_f32(struct bare_reader *ctx, float *x); +bare_error bare_put_f64(struct bare_writer *ctx, double x); +bare_error bare_get_f64(struct bare_reader *ctx, double *x); + +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, 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, 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, const char *src, uint64_t sz); +bare_error bare_get_str(struct bare_reader *ctx, char *dst, uint64_t sz); + +/* Note that the _str implementation here does not check for UTF-8 validity. */ + +#endif /* BARE_H */ diff --git a/git2d/cmd1.c b/git2d/cmd1.c new file mode 100644 index 0000000..a7d8b07 --- /dev/null +++ b/git2d/cmd1.c @@ -0,0 +1,129 @@ +/*- + * SPDX-License-Identifier: AGPL-3.0-only + * SPDX-FileCopyrightText: Copyright (c) 2025 Runxi Yu <https://runxiyu.org> + */ + +#include "x.h" + +int cmd_index(git_repository *repo, struct bare_writer *writer) +{ + /* HEAD tree */ + + git_object *obj = NULL; + int err = git_revparse_single(&obj, repo, "HEAD^{tree}"); + if (err != 0) { + bare_put_uint(writer, 4); + return -1; + } + git_tree *tree = (git_tree *) obj; + + /* README */ + + git_tree_entry *entry = NULL; + err = git_tree_entry_bypath(&entry, tree, "README.md"); + if (err != 0) { + bare_put_uint(writer, 5); + git_tree_free(tree); + return -1; + } + git_otype objtype = git_tree_entry_type(entry); + if (objtype != GIT_OBJECT_BLOB) { + bare_put_uint(writer, 6); + git_tree_entry_free(entry); + git_tree_free(tree); + return -1; + } + git_object *obj2 = NULL; + err = git_tree_entry_to_object(&obj2, repo, entry); + if (err != 0) { + bare_put_uint(writer, 7); + git_tree_entry_free(entry); + git_tree_free(tree); + return -1; + } + git_blob *blob = (git_blob *) obj2; + const void *content = git_blob_rawcontent(blob); + if (content == NULL) { + bare_put_uint(writer, 8); + git_blob_free(blob); + git_tree_entry_free(entry); + git_tree_free(tree); + return -1; + } + bare_put_uint(writer, 0); + bare_put_data(writer, content, git_blob_rawsize(blob)); + + /* Commits */ + + /* TODO BUG: This might be a different commit from the displayed README due to races */ + + git_revwalk *walker = NULL; + if (git_revwalk_new(&walker, repo) != 0) { + bare_put_uint(writer, 9); + git_blob_free(blob); + git_tree_entry_free(entry); + git_tree_free(tree); + return -1; + } + + if (git_revwalk_push_head(walker) != 0) { + bare_put_uint(writer, 9); + git_revwalk_free(walker); + git_blob_free(blob); + git_tree_entry_free(entry); + git_tree_free(tree); + return -1; + } + + int count = 0; + git_oid oid; + while (count < 3 && git_revwalk_next(&oid, walker) == 0) { + git_commit *commit = NULL; + if (git_commit_lookup(&commit, repo, &oid) != 0) + break; + + const char *msg = git_commit_summary(commit); + const git_signature *author = git_commit_author(commit); + + /* ID */ + bare_put_data(writer, oid.id, GIT_OID_RAWSZ); + + /* Title */ + size_t msg_len = msg ? strlen(msg) : 0; + bare_put_data(writer, (const uint8_t *)(msg ? msg : ""), + msg_len); + + /* Author's name */ + const char *author_name = author ? author->name : ""; + bare_put_data(writer, (const uint8_t *)author_name, + strlen(author_name)); + + /* Author's email */ + const char *author_email = author ? author->email : ""; + bare_put_data(writer, (const uint8_t *)author_email, + strlen(author_email)); + + /* Author's date */ + /* TODO: Pass the integer instead of a string */ + time_t time = git_commit_time(commit); + char timebuf[64]; + struct tm *tm = localtime(&time); + if (tm) + strftime(timebuf, sizeof(timebuf), "%Y-%m-%d %H:%M:%S", + tm); + else + strcpy(timebuf, "unknown"); + bare_put_data(writer, (const uint8_t *)timebuf, + strlen(timebuf)); + + git_commit_free(commit); + count++; + } + + git_revwalk_free(walker); + git_blob_free(blob); + git_tree_entry_free(entry); + git_tree_free(tree); + + return 0; +} diff --git a/git2d/cmd2.c b/git2d/cmd2.c new file mode 100644 index 0000000..dd72ddb --- /dev/null +++ b/git2d/cmd2.c @@ -0,0 +1,126 @@ +/*- + * SPDX-License-Identifier: AGPL-3.0-only + * SPDX-FileCopyrightText: Copyright (c) 2025 Runxi Yu <https://runxiyu.org> + */ + +#include "x.h" + +int +cmd_treeraw(git_repository *repo, struct bare_reader *reader, + struct bare_writer *writer) +{ + /* Path */ + char path[4096] = { 0 }; + int err = bare_get_data(reader, (uint8_t *) path, sizeof(path) - 1); + if (err != BARE_ERROR_NONE) { + bare_put_uint(writer, 11); + return -1; + } + path[sizeof(path) - 1] = '\0'; + + /* HEAD^{tree} */ + git_object *head_obj = NULL; + err = git_revparse_single(&head_obj, repo, "HEAD^{tree}"); + if (err != 0) { + bare_put_uint(writer, 4); + return -1; + } + git_tree *tree = (git_tree *) head_obj; + + /* Path in tree */ + git_tree_entry *entry = NULL; + git_otype objtype; + if (strlen(path) == 0) { + entry = NULL; + objtype = GIT_OBJECT_TREE; + } else { + err = git_tree_entry_bypath(&entry, tree, path); + if (err != 0) { + bare_put_uint(writer, 3); + git_tree_free(tree); + return 0; + } + objtype = git_tree_entry_type(entry); + } + + if (objtype == GIT_OBJECT_TREE) { + /* Tree */ + git_object *tree_obj = NULL; + if (entry == NULL) { + tree_obj = (git_object *) tree; + } else { + err = git_tree_entry_to_object(&tree_obj, repo, entry); + if (err != 0) { + bare_put_uint(writer, 7); + goto cleanup; + } + } + git_tree *subtree = (git_tree *) tree_obj; + + size_t count = git_tree_entrycount(subtree); + bare_put_uint(writer, 0); + bare_put_uint(writer, 1); + bare_put_uint(writer, count); + for (size_t i = 0; i < count; i++) { + const git_tree_entry *subentry = + git_tree_entry_byindex(subtree, i); + const char *name = git_tree_entry_name(subentry); + git_otype type = git_tree_entry_type(subentry); + uint32_t mode = git_tree_entry_filemode(subentry); + + uint8_t entry_type = 0; + uint64_t size = 0; + + if (type == GIT_OBJECT_TREE) { + entry_type = 1; + } else if (type == GIT_OBJECT_BLOB) { + entry_type = 2; + + git_object *subobj = NULL; + if (git_tree_entry_to_object + (&subobj, repo, subentry) == 0) { + git_blob *b = (git_blob *) subobj; + size = git_blob_rawsize(b); + git_blob_free(b); + } + } + + bare_put_uint(writer, entry_type); + bare_put_uint(writer, mode); + bare_put_uint(writer, size); + bare_put_data(writer, (const uint8_t *)name, + strlen(name)); + } + if (entry != NULL) { + git_tree_free(subtree); + } + } else if (objtype == GIT_OBJECT_BLOB) { + /* Blob */ + git_object *blob_obj = NULL; + err = git_tree_entry_to_object(&blob_obj, repo, entry); + if (err != 0) { + bare_put_uint(writer, 7); + goto cleanup; + } + git_blob *blob = (git_blob *) blob_obj; + const void *content = git_blob_rawcontent(blob); + if (content == NULL) { + bare_put_uint(writer, 8); + git_blob_free(blob); + goto cleanup; + } + bare_put_uint(writer, 0); + bare_put_uint(writer, 2); + bare_put_data(writer, content, git_blob_rawsize(blob)); + git_blob_free(blob); + } else { + /* Unknown */ + bare_put_uint(writer, -1); + } + + cleanup: + if (entry != NULL) + git_tree_entry_free(entry); + git_tree_free(tree); + return 0; +} diff --git a/git2d/main.c b/git2d/main.c new file mode 100644 index 0000000..9140c1d --- /dev/null +++ b/git2d/main.c @@ -0,0 +1,82 @@ +/*- + * SPDX-License-Identifier: AGPL-3.0-only + * SPDX-FileCopyrightText: Copyright (c) 2025 Runxi Yu <https://runxiyu.org> + */ + +/* + * TODO: Pool repositories (and take care of thread safety) + * libgit2 has a nice builtin per-repo cache that we could utilize this way. + */ + +#include "x.h" + +int main(int argc, char **argv) +{ + if (argc != 2) { + errx(1, "provide one argument: the socket path"); + } + + signal(SIGPIPE, SIG_IGN); + + git_libgit2_init(); + + int sock; + if ((sock = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0)) < 0) + err(1, "socket"); + + struct sockaddr_un addr; + memset(&addr, 0, sizeof(addr)); + addr.sun_family = AF_UNIX; + strcpy(addr.sun_path, argv[1]); + + umask(0077); + + if (bind(sock, (struct sockaddr *)&addr, sizeof(struct sockaddr_un))) { + if (errno == EADDRINUSE) { + unlink(argv[1]); + if (bind + (sock, (struct sockaddr *)&addr, + sizeof(struct sockaddr_un))) + err(1, "bind"); + } else { + err(1, "bind"); + } + } + + listen(sock, 128); + + pthread_attr_t pthread_attr; + + if (pthread_attr_init(&pthread_attr) != 0) + err(1, "pthread_attr_init"); + + if (pthread_attr_setdetachstate(&pthread_attr, PTHREAD_CREATE_DETACHED) != 0) + err(1, "pthread_attr_setdetachstate"); + + for (;;) { + int *conn = malloc(sizeof(int)); + if (conn == NULL) { + warn("malloc"); + continue; + } + + *conn = accept(sock, 0, 0); + if (*conn == -1) { + free(conn); + warn("accept"); + continue; + } + + pthread_t thread; + + if (pthread_create (&thread, &pthread_attr, session, (void *)conn) != 0) { + close(*conn); + free(conn); + warn("pthread_create"); + } + } + + close(sock); + + git_libgit2_shutdown(); +} diff --git a/git2d/rw.c b/git2d/rw.c new file mode 100644 index 0000000..09398c2 --- /dev/null +++ b/git2d/rw.c @@ -0,0 +1,34 @@ +/*- + * SPDX-License-Identifier: AGPL-3.0-only + * SPDX-FileCopyrightText: Copyright (c) 2025 Runxi Yu <https://runxiyu.org> + */ + +#include "x.h" + +bare_error conn_read(void *buffer, void *dst, uint64_t sz) +{ + conn_io_t *io = buffer; + ssize_t rsz = read(io->fd, dst, sz); + return (rsz == (ssize_t) sz) ? BARE_ERROR_NONE : BARE_ERROR_READ_FAILED; +} + +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; +} diff --git a/git2d/session.c b/git2d/session.c new file mode 100644 index 0000000..0a945ee --- /dev/null +++ b/git2d/session.c @@ -0,0 +1,78 @@ +/*- + * SPDX-License-Identifier: AGPL-3.0-only + * SPDX-FileCopyrightText: Copyright (c) 2025 Runxi Yu <https://runxiyu.org> + */ + +#include "x.h" + +void *session(void *_conn) +{ + int conn = *(int *)_conn; + free((int *)_conn); + + int err; + + conn_io_t io = {.fd = conn }; + struct bare_reader reader = { + .buffer = &io, + .read = conn_read, + }; + struct bare_writer writer = { + .buffer = &io, + .write = conn_write, + }; + + /* Repo path */ + char path[4096] = { 0 }; + err = bare_get_data(&reader, (uint8_t *) path, sizeof(path) - 1); + if (err != BARE_ERROR_NONE) { + goto close; + } + path[sizeof(path) - 1] = '\0'; + + /* Open repo */ + git_repository *repo = NULL; + 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) { + bare_put_uint(&writer, 1); + goto close; + } + + /* Command */ + uint64_t cmd = 0; + err = bare_get_uint(&reader, &cmd); + if (err != BARE_ERROR_NONE) { + bare_put_uint(&writer, 2); + goto free_repo; + } + switch (cmd) { + case 1: + err = cmd_index(repo, &writer); + if (err != 0) + goto free_repo; + break; + case 2: + err = cmd_treeraw(repo, &reader, &writer); + if (err != 0) + goto free_repo; + break; + case 0: + bare_put_uint(&writer, 3); + goto free_repo; + default: + bare_put_uint(&writer, 3); + goto free_repo; + } + + free_repo: + git_repository_free(repo); + + close: + close(conn); + + return NULL; +} diff --git a/git2d/x.h b/git2d/x.h new file mode 100644 index 0000000..a6da50f --- /dev/null +++ b/git2d/x.h @@ -0,0 +1,38 @@ +/*- + * SPDX-License-Identifier: AGPL-3.0-only + * SPDX-FileCopyrightText: Copyright (c) 2025 Runxi Yu <https://runxiyu.org> + */ + +#ifndef X_H +#define X_H + +#include <err.h> +#include <errno.h> +#include <git2.h> +#include <pthread.h> +#include <signal.h> +#include <sys/socket.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <sys/un.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "bare.h" + +typedef struct { + int fd; +} conn_io_t; + + +bare_error conn_read(void *buffer, void *dst, uint64_t sz); +bare_error conn_write(void *buffer, const void *src, uint64_t sz); + +void * session(void *_conn); + +int cmd_index(git_repository *repo, struct bare_writer *writer); +int cmd_treeraw(git_repository *repo, struct bare_reader *reader, struct bare_writer *writer); + +#endif // X_H |