| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | #include <git2.h> | ||
| 2 | #include <glib.h> | ||
| 3 | #include <stdio.h> | ||
| 4 | #include <stdlib.h> | ||
| 5 | #include <unistd.h> | ||
| 6 | #include "examples/signature_extract.h" | ||
| 7 | |||
| 8 | #define GET_CWD getcwd | ||
| 9 | |||
| 10 | /** | ||
| 11 | * Private helper method for error message output | ||
| 12 | * | ||
| 13 | * @param error Error code | ||
| 14 | * @param message Custom message for error | ||
| 15 | */ | ||
| 16 | |||
| 17 | ✗ | static void log_git_error(int error, const char* message) { | |
| 18 | ✗ | if (error < 0) { | |
| 19 | ✗ | const git_error* e = giterr_last(); | |
| 20 | ✗ | g_printerr("Error %d: %s - %s\n", error, message, | |
| 21 | e ? e->message : "Unknown"); | ||
| 22 | } | ||
| 23 | ✗ | } | |
| 24 | |||
| 25 | /** | ||
| 26 | * Gets the Git Repository Path for the current working directory. | ||
| 27 | * | ||
| 28 | * @return The cwd git repository path. Returns NULL on failure. | ||
| 29 | */ | ||
| 30 | ✗ | char* find_git_repo_path(void) { | |
| 31 | ✗ | git_buf repo_path_buf = {0}; | |
| 32 | ✗ | char* repo_path = NULL; | |
| 33 | char cwd[1024]; | ||
| 34 | |||
| 35 | ✗ | if (!GET_CWD(cwd, sizeof(cwd))) { | |
| 36 | ✗ | perror("Could not get current working directory"); | |
| 37 | ✗ | return NULL; | |
| 38 | } | ||
| 39 | |||
| 40 | ✗ | int error = git_repository_discover(&repo_path_buf, cwd, 1, NULL); | |
| 41 | ✗ | if (error < 0) { | |
| 42 | ✗ | log_git_error(error, "Failed to discover repository"); | |
| 43 | ✗ | git_buf_dispose(&repo_path_buf); | |
| 44 | ✗ | return NULL; | |
| 45 | } | ||
| 46 | |||
| 47 | ✗ | repo_path = malloc(repo_path_buf.size + 1); | |
| 48 | ✗ | if (repo_path) { | |
| 49 | ✗ | g_strlcpy(repo_path, repo_path_buf.ptr, repo_path_buf.size + 1); | |
| 50 | ✗ | repo_path[repo_path_buf.size] = '\0'; | |
| 51 | } | ||
| 52 | |||
| 53 | ✗ | git_buf_dispose(&repo_path_buf); | |
| 54 | ✗ | return repo_path; | |
| 55 | } | ||
| 56 | |||
| 57 | /** | ||
| 58 | * Gets the SHA string of the commit that HEAD points to. AKA the | ||
| 59 | * most recent commit. | ||
| 60 | * | ||
| 61 | * @param repo A previously opened git_repository object. | ||
| 62 | * @return A dynamically allocated 40-character string with the SHA, | ||
| 63 | * which the caller must free. Returns NULL on failure. | ||
| 64 | */ | ||
| 65 | ✗ | char* get_head_commit_sha(git_repository* repo) { | |
| 66 | ✗ | if (!repo) { | |
| 67 | ✗ | g_printerr("Error: get_head_commit_sha called with NULL repository.\n"); | |
| 68 | ✗ | return NULL; | |
| 69 | } | ||
| 70 | |||
| 71 | git_oid oid; | ||
| 72 | ✗ | char* sha_string = NULL; | |
| 73 | |||
| 74 | ✗ | int error = git_reference_name_to_id(&oid, repo, "HEAD"); | |
| 75 | ✗ | if (error < 0) { | |
| 76 | ✗ | log_git_error(error, "Failed to resolve HEAD to a commit"); | |
| 77 | ✗ | return NULL; | |
| 78 | } | ||
| 79 | |||
| 80 | ✗ | sha_string = malloc(GIT_OID_HEXSZ + 1); | |
| 81 | ✗ | if (sha_string) { | |
| 82 | ✗ | git_oid_tostr(sha_string, GIT_OID_HEXSZ + 1, &oid); | |
| 83 | } | ||
| 84 | |||
| 85 | ✗ | return sha_string; | |
| 86 | } | ||
| 87 | |||
| 88 | /** | ||
| 89 | * Gets the GPG Signature for the git commit given. | ||
| 90 | * | ||
| 91 | * @param repo_path A path to the git repository for the commit | ||
| 92 | * @param commit_sha The sha for the commit we want to check | ||
| 93 | * @return A GPG Signature. Returns NULL on failure. | ||
| 94 | */ | ||
| 95 | // NOLINTNEXTLINE(bugprone-easily-swappable-parameters) | ||
| 96 | ✗ | char* signature_extract(const char* repo_path, const char* commit_sha) { | |
| 97 | ✗ | git_repository* repo = NULL; | |
| 98 | git_oid oid; | ||
| 99 | ✗ | git_buf signature_buf = {0}; | |
| 100 | ✗ | git_buf signed_data_buf = {0}; | |
| 101 | ✗ | char* signature_string = NULL; | |
| 102 | |||
| 103 | // Gets the Git Repository Object (repo) | ||
| 104 | ✗ | int error = git_repository_open(&repo, repo_path); | |
| 105 | ✗ | if (error < 0) { | |
| 106 | ✗ | log_git_error(error, "Failed to open repository"); | |
| 107 | ✗ | return NULL; | |
| 108 | } | ||
| 109 | |||
| 110 | // Gets the Git Object ID | ||
| 111 | ✗ | error = git_oid_fromstr(&oid, commit_sha); // Git Object ID | |
| 112 | ✗ | if (error < 0) { | |
| 113 | ✗ | log_git_error(error, "Failed to parse commit SHA"); | |
| 114 | ✗ | git_repository_free(repo); | |
| 115 | ✗ | return NULL; | |
| 116 | } | ||
| 117 | |||
| 118 | // Extracts GPG Signature | ||
| 119 | ✗ | error = git_commit_extract_signature(&signature_buf, &signed_data_buf, repo, | |
| 120 | &oid, NULL); | ||
| 121 | ✗ | if (error == GIT_ENOTFOUND) { | |
| 122 | ✗ | g_printerr("No GPG signature found on commit %s\n", commit_sha); | |
| 123 | |||
| 124 | ✗ | } else if (error < 0) { | |
| 125 | ✗ | log_git_error(error, "Failed to extract signature"); | |
| 126 | } else { | ||
| 127 | ✗ | signature_string = malloc(signature_buf.size + 1); | |
| 128 | ✗ | if (signature_string) { | |
| 129 | ✗ | g_strlcpy(signature_string, signature_buf.ptr, | |
| 130 | ✗ | signature_buf.size + 1); | |
| 131 | } | ||
| 132 | } | ||
| 133 | |||
| 134 | ✗ | git_buf_dispose(&signature_buf); | |
| 135 | ✗ | git_buf_dispose(&signed_data_buf); | |
| 136 | ✗ | git_repository_free(repo); | |
| 137 | |||
| 138 | ✗ | return signature_string; | |
| 139 | } | ||
| 140 |