Lindenii Project Forge
git2d: Add a basic command for tree
/*- * SPDX-License-Identifier: AGPL-3.0-only * SPDX-FileCopyrightText: Copyright (c) 2025 Runxi Yu <https://runxiyu.org> */ #include "x.h" int cmd2(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, 10); 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, 11); 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, 3); 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, 3); goto cleanup; } git_blob *blob = (git_blob *)blob_obj; const void *content = git_blob_rawcontent(blob); if (content == NULL) { bare_put_uint(writer, 3); 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, 3); } cleanup: if (entry != NULL) git_tree_entry_free(entry); git_tree_free(tree); return 0; }
/*- * 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 = cmd1(repo, &writer); if (err != 0) goto free_repo; break;
case 2: err = cmd2(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; }
/*- * SPDX-License-Identifier: AGPL-3.0-only * SPDX-FileCopyrightText: Copyright (c) 2025 Runxi Yu <https://runxiyu.org> */ #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" #ifndef X_H #define X_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 cmd1(git_repository *repo, struct bare_writer *writer);
int cmd2(git_repository *repo, struct bare_reader *reader, struct bare_writer *writer);
#endif // X_H